From afafab5a16a9b9b72a7dec9b69f01db6ed140cb3 Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Sat, 2 Oct 2021 19:02:10 +0530 Subject: [PATCH] Implemented references and definition Removed usage of custom LSP data classes --- app/build.gradle | 1 - app/src/main/assets/data/jls.jar | Bin 7085609 -> 7093278 bytes .../com/itsaky/androidide/EditorActivity.java | 76 +--- .../adapters/CompletionListAdapter.java | 4 - .../adapters/DiagnosticItemAdpater.java | 12 +- .../adapters/EditorPagerAdapter.java | 5 +- .../com/itsaky/androidide/app/StudioApp.java | 36 +- .../androidide/fragments/EditorFragment.java | 60 +-- .../handlers/FileOptionsHandler.java | 6 +- .../androidide/handlers/IDEHandler.java | 12 - .../androidide/handlers/jls/JLSHandler.java | 322 ------------- .../handlers/jls/LanguageClientHandler.java | 254 ----------- .../interfaces/DiagnosticClickListener.java | 2 +- .../androidide/interfaces/JLSRequestor.java | 28 -- .../interfaces/LanguageServerListener.java | 5 - .../language/groovy/GroovyAutoComplete.java | 6 +- .../language/java/JavaAutoComplete.java | 11 +- .../language/java/JavaLanguage.java | 11 +- .../language/java/JavaLanguageAnalyzer.java | 10 - .../java/server/JavaLanguageServer.java | 429 ------------------ .../language/xml/XMLAutoComplete.java | 6 - .../androidide/lsp/IDELanguageClient.java | 189 +++++++- .../java/com/itsaky/androidide/lsp/LSP.java | 123 ++++- .../lsp/client/java/JavaLanguageClient.java | 4 - .../androidide/models/CompletionEdit.java | 25 - .../models/CompletionItemWrapper.java | 135 ------ .../androidide/models/CompletionListItem.java | 214 --------- .../androidide/models/DiagnosticGroup.java | 2 +- .../androidide/models/GradleSuggestItem.java | 58 --- .../androidide/services/IDEService.java | 17 +- .../lexer/impls/java/JavaLexerImpl.java | 198 +------- .../editor/text/TextAnalyzeResult.java | 9 +- .../rosemoe/editor/widget/CodeEditor.java | 253 +++++++---- .../editor/widget/DiagnosticWindow.java | 22 +- .../widget/EditorTextActionModeStarter.java | 12 +- lsp/.gitignore | 85 ---- lsp/build.gradle | 23 - lsp/proguard-rules.pro | 17 - lsp/src/main/AndroidManifest.xml | 1 - .../java/com/itsaky/lsp/CancelParams.java | 8 - .../main/java/com/itsaky/lsp/CodeAction.java | 44 -- .../com/itsaky/lsp/CodeActionContext.java | 13 - .../java/com/itsaky/lsp/CodeActionKind.java | 11 - .../java/com/itsaky/lsp/CodeActionParams.java | 14 - .../main/java/com/itsaky/lsp/CodeLens.java | 23 - .../java/com/itsaky/lsp/CodeLensParams.java | 14 - lsp/src/main/java/com/itsaky/lsp/Command.java | 24 - .../java/com/itsaky/lsp/CompletionItem.java | 54 --- .../com/itsaky/lsp/CompletionItemKind.java | 60 --- .../java/com/itsaky/lsp/CompletionList.java | 29 -- .../com/itsaky/lsp/CompletionTriggerKind.java | 18 - .../main/java/com/itsaky/lsp/Diagnostic.java | 25 - .../com/itsaky/lsp/DiagnosticSeverity.java | 13 - .../java/com/itsaky/lsp/DiagnosticTag.java | 5 - .../lsp/DidChangeConfigurationParams.java | 9 - .../lsp/DidChangeTextDocumentParams.java | 13 - .../lsp/DidChangeWatchedFilesParams.java | 19 - .../lsp/DidChangeWorkspaceFoldersParams.java | 8 - .../lsp/DidCloseTextDocumentParams.java | 9 - .../com/itsaky/lsp/DidOpenTextDocument.java | 8 - .../itsaky/lsp/DidOpenTextDocumentParams.java | 15 - .../itsaky/lsp/DidSaveTextDocumentParams.java | 12 - .../itsaky/lsp/DocumentFormattingParams.java | 12 - .../com/itsaky/lsp/DocumentHighlight.java | 12 - .../com/itsaky/lsp/DocumentHighlightKind.java | 5 - .../java/com/itsaky/lsp/DocumentLink.java | 16 - .../com/itsaky/lsp/DocumentLinkParams.java | 15 - .../java/com/itsaky/lsp/DocumentSymbol.java | 27 -- .../com/itsaky/lsp/DocumentSymbolParams.java | 15 - .../main/java/com/itsaky/lsp/ErrorCodes.java | 18 - .../java/com/itsaky/lsp/FileChangeType.java | 5 - .../main/java/com/itsaky/lsp/FileEvent.java | 18 - .../java/com/itsaky/lsp/FoldingRange.java | 30 -- .../java/com/itsaky/lsp/FoldingRangeKind.java | 10 - .../com/itsaky/lsp/FoldingRangeParams.java | 9 - .../com/itsaky/lsp/FormattingOptions.java | 19 - lsp/src/main/java/com/itsaky/lsp/Hover.java | 23 - .../java/com/itsaky/lsp/InitializeParams.java | 30 -- .../java/com/itsaky/lsp/InitializeResult.java | 16 - .../java/com/itsaky/lsp/InsertTextFormat.java | 5 - .../main/java/com/itsaky/lsp/JavaColors.java | 71 --- .../itsaky/lsp/JavaReportProgressParams.java | 38 -- .../itsaky/lsp/JavaStartProgressParams.java | 23 - .../java/com/itsaky/lsp/LanguageClient.java | 25 - .../java/com/itsaky/lsp/LanguageServer.java | 120 ----- .../main/java/com/itsaky/lsp/Location.java | 27 -- .../java/com/itsaky/lsp/MarkedString.java | 49 -- .../java/com/itsaky/lsp/MarkupContent.java | 18 - .../main/java/com/itsaky/lsp/MarkupKind.java | 5 - lsp/src/main/java/com/itsaky/lsp/Message.java | 18 - .../main/java/com/itsaky/lsp/MessageType.java | 12 - .../com/itsaky/lsp/NotificationMessage.java | 13 - .../com/itsaky/lsp/ParameterInformation.java | 11 - .../main/java/com/itsaky/lsp/Position.java | 37 -- .../itsaky/lsp/PublishDiagnosticsParams.java | 24 - lsp/src/main/java/com/itsaky/lsp/Range.java | 40 -- .../java/com/itsaky/lsp/ReferenceContext.java | 15 - .../java/com/itsaky/lsp/ReferenceParams.java | 9 - .../com/itsaky/lsp/RegistrationParams.java | 16 - .../java/com/itsaky/lsp/RenameParams.java | 16 - .../java/com/itsaky/lsp/RenameResponse.java | 12 - .../java/com/itsaky/lsp/RequestMessage.java | 16 - .../java/com/itsaky/lsp/ResponseError.java | 23 - .../com/itsaky/lsp/ShowMessageParams.java | 12 - .../java/com/itsaky/lsp/SignatureHelp.java | 23 - .../com/itsaky/lsp/SignatureInformation.java | 24 - .../com/itsaky/lsp/SymbolInformation.java | 21 - .../main/java/com/itsaky/lsp/SymbolKind.java | 30 -- .../lsp/TextDocumentContentChangeEvent.java | 14 - .../java/com/itsaky/lsp/TextDocumentEdit.java | 12 - .../itsaky/lsp/TextDocumentIdentifier.java | 16 - .../java/com/itsaky/lsp/TextDocumentItem.java | 18 - .../lsp/TextDocumentPositionParams.java | 19 - .../itsaky/lsp/TextDocumentSaveReason.java | 5 - .../main/java/com/itsaky/lsp/TextEdit.java | 26 -- .../lsp/VersionedTextDocumentIdentifier.java | 12 - .../lsp/WillSaveTextDocumentParams.java | 12 - .../java/com/itsaky/lsp/WorkspaceEdit.java | 12 - .../java/com/itsaky/lsp/WorkspaceFolder.java | 13 - .../lsp/WorkspaceFoldersChangeEvent.java | 12 - .../com/itsaky/lsp/WorkspaceSymbolParams.java | 14 - settings.gradle | 1 - 122 files changed, 530 insertions(+), 3820 deletions(-) delete mode 100644 app/src/main/java/com/itsaky/androidide/handlers/jls/JLSHandler.java delete mode 100644 app/src/main/java/com/itsaky/androidide/handlers/jls/LanguageClientHandler.java delete mode 100644 app/src/main/java/com/itsaky/androidide/interfaces/JLSRequestor.java delete mode 100644 app/src/main/java/com/itsaky/androidide/interfaces/LanguageServerListener.java delete mode 100644 app/src/main/java/com/itsaky/androidide/language/java/server/JavaLanguageServer.java delete mode 100644 app/src/main/java/com/itsaky/androidide/models/CompletionEdit.java delete mode 100644 app/src/main/java/com/itsaky/androidide/models/CompletionItemWrapper.java delete mode 100644 app/src/main/java/com/itsaky/androidide/models/CompletionListItem.java delete mode 100644 app/src/main/java/com/itsaky/androidide/models/GradleSuggestItem.java delete mode 100644 lsp/.gitignore delete mode 100644 lsp/build.gradle delete mode 100644 lsp/proguard-rules.pro delete mode 100644 lsp/src/main/AndroidManifest.xml delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CancelParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CodeAction.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CodeActionContext.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CodeActionKind.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CodeActionParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CodeLens.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CodeLensParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/Command.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CompletionItem.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CompletionItemKind.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CompletionList.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/CompletionTriggerKind.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/Diagnostic.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DiagnosticSeverity.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DiagnosticTag.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DidChangeConfigurationParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DidChangeTextDocumentParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DidChangeWatchedFilesParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DidChangeWorkspaceFoldersParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DidCloseTextDocumentParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DidOpenTextDocument.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DidOpenTextDocumentParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DidSaveTextDocumentParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DocumentFormattingParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DocumentHighlight.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DocumentHighlightKind.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DocumentLink.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DocumentLinkParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DocumentSymbol.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/DocumentSymbolParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/ErrorCodes.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/FileChangeType.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/FileEvent.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/FoldingRange.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/FoldingRangeKind.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/FoldingRangeParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/FormattingOptions.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/Hover.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/InitializeParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/InitializeResult.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/InsertTextFormat.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/JavaColors.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/JavaReportProgressParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/JavaStartProgressParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/LanguageClient.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/LanguageServer.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/Location.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/MarkedString.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/MarkupContent.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/MarkupKind.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/Message.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/MessageType.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/NotificationMessage.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/ParameterInformation.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/Position.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/PublishDiagnosticsParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/Range.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/ReferenceContext.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/ReferenceParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/RegistrationParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/RenameParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/RenameResponse.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/RequestMessage.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/ResponseError.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/ShowMessageParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/SignatureHelp.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/SignatureInformation.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/SymbolInformation.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/SymbolKind.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/TextDocumentContentChangeEvent.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/TextDocumentEdit.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/TextDocumentIdentifier.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/TextDocumentItem.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/TextDocumentPositionParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/TextDocumentSaveReason.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/TextEdit.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/VersionedTextDocumentIdentifier.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/WillSaveTextDocumentParams.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/WorkspaceEdit.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/WorkspaceFolder.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/WorkspaceFoldersChangeEvent.java delete mode 100644 lsp/src/main/java/com/itsaky/lsp/WorkspaceSymbolParams.java diff --git a/app/build.gradle b/app/build.gradle index 46e12a203..ec604dd42 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -131,7 +131,6 @@ dependencies { // Local projects implementation project(':api-info') implementation project(':treeview') - implementation project(':lsp') implementation project(':emulator') implementation project(':emulatorview') implementation project(':javapoet') diff --git a/app/src/main/assets/data/jls.jar b/app/src/main/assets/data/jls.jar index 91765865776a0893c4b1adb7983a61459eae7fff..3b8301fea1fc2e24e9dc941f8e5b6c73ff6ab017 100644 GIT binary patch delta 58108 zcmYJ41y~f$^YH2JE(rkvMe^wGZn&dUy1O~*kWxV6q`O1<1ZhMBq(d4cB$bdx;XSzD z_x=0u=;xW8otd4Ton23_vZEd~@2VaZUt0|o4F~DrSCF%83O);JptEcQ00KaU08k(R zR0seK0ziiVFdzU-2mlKLz=i;DAOKtl01pDdhX4p5073|W2m&C607xJJQV4(y0w9L~ zC?Ehz2!IL#poRcwAOKnjfDQt90s+uN01OZSBLu(%0X&5Om>~cb2!Is=cm@HmK>+L! z00#u{90GU&0dPV9FChRf2!I;`;DG>mApkxIfFA;Y$0h&)2toit5P&cQAOZo1LI7eA zfH(vo0Rc!t08$WuGz1_60mwoCau9$#1fT!`C_(^A5P&iSpaKD?LI7$IfI0-A0Rd=2 z09p`$HUyvp0q8;idJup<1Ypnt0D6p|`a8=)%SV9EP<`PrF#_a#l-!R1`5poA4akM+ z2OrA(2Bd@jt~SDjCVm6rJdVLdyr@3#vC(h97mrG}-+(V40d9y6x<+Jz0o51<;t0YG z=sl+Yf4`B#|8)1V=XSF4v$FB#_O^Aka`SP7)BkPMgU?4RexpF5$Kc?`>7b!~&X~{| zxXniq+%X+=b`(hXe@;=yfUT$=@W~xxz_G{Z-i!maQ4Qdd^>N@kRA*;dnC}Eo0{M|z zCV?-I@!>K(rT4`A*YL2spdLOTdg!s0GdYZL8i;zJopKFXJV-2KJenvqtF4+1)(+;u$=l3T|QLi0LTFCfjHyB z77u}#h*3v$1-4XG09Rr0BbaetWLy+MgpcaCv&VU*Sx;g(ZU7f{k(0#Z|ZRq+ckRBF#3B*FE z#9sZU!cXUWAO&}K2kj++FHQOj2oL(w#Tf_2bOTgDD7)SQl@avuFOU~OhyQ?31jXFL z{XTASvBuN*W4O1nhvm~lKe#!QWw<$GK&g;HH;ArV1QmAWZjq`Q3UJTzjVvrMpU?iabE#iO_RDuY7SHjwt5FXDbD9;Q$^gBBc78K9hnF2OX4x&b= z(6F)v+{0HFfk+f%4+st2!y1V0N86haMx*X{$=(SYD*!3|Dp zv>z zG7PBBAm|CS{tAc=4fA)#gXL;~UZ6Z`k7$9C5cAA*K$-}u(*@}v2u&Ykgdj@;kQ;&~ zfgn2si5h}@k?|iqh3x(aMS=wE0>eOo$XE|XM_lr< zp;qxA=Ev3q;|K>~AiUl5xjnsrdrOBhpuki9*tqN=&ZOmm5%4rUx`=!@m=Dwz1>!-_ zVf244SYklx$OI2A2&&e)wBSk9M1gY0fY_lDuboL?A78`k@o`z#sH6>Na7Rf9N8x{f zc+i5^&ZJP2IMCgrdDD2fBkTuLc;#r|J?Nw#Jac0y@a1>M!Y`D$G7u4TGXb>ss63wd zP}C1m3BQGB?vdP+;3f6ATwxEkJ?N7!@a2Asb0&eVB!f;KH6~L)S_l_GF6fH;P~H-_ z3yT9FE)19oLPl6IP6PQNR`hR}yXFOaMJOmxMkmlS7+MBM7NMg8eP{s>-hLlP2MWyjPp>-np?y5a_VVC*k0}ZELZ5p$Yj2=jG4R|oo&s^9Ja6Ig z!c#&3^(z1!Jx*{a1o)d!j^he!M9=$~uAyF0j} zGAQo^hzXjM;Y0(p3;p@5z|=0N)!2>wKQ z7*z$jfBFA!4<^|0D2NC#(5`y;djY;rYKX>_iwigWAshbokQoPUJ_f}$0Z-&(P`nfA z1qaZcW_T6+S7}&KB6y?D=!VbgorJd}xG&g;sfVNeKs(bQRm4<^0;IV=P;e)FDq%YO zRJ+Z>7xkzUJO?l9$K{ocMSY|Xzd#y%k8j_5216H;$G3tTpJ6cSBOMADjv?L(okE5*h?m5oh@m8cXvGbc zPzm67yIy$y$@D5J64E6$^v8`MHFSN;5DoT5%J2&H@#>G2GbBZMq&x+~@92*dpk`Qs z{y4eyPp1tNIucSGE@JYVQfD%liH_k5^v4?|4rq9RNBnSmq}E73eG0$vf5APyfa(kw zQo_n@4CN44{V!X?KFmiov^4%1BDg(0TqGn`D6fto6?C=CnFzM)YDj}HiSBKaGW?7fCC)X} zL4B0j78qh;KazW;;TwePzQ%9^?=kILZH6`|kEGgRc!5O#KOA}rmc5AvWJpMRFQG)< zhBQzxz7ZZYpa%Y+2_G=DAR~UzxmdKtQH7_#6zzX&qkv&78rmUDxi1^4Vm%t|*fM;L z@kojXh7O3)hF^wH@gIw6?#56Ag&1B|dRL)!{8xlXNIzMTkoX=_MFCx^b7p`U{4+!$ zdek+>H_E^63SjKyZ&Bq}(RzV?sI0air zUpG(To8tj5J`p4&s7sqOJ(xw_-Nx6|*3C!G!OG3vR@ut!m5Z$xmyL^+w|8!ukrt^A z+2Fl@J6@Vq3ujUIQ)S0e1qx3YvIGoe85`_p9r)9V;Tth>keXWCaK38+y0thD*L>ifaTvqOCsRrnH{jzY8q9@_p4&@ zG%bsJj$SppuJi=6ormV0i;WA%mOcAtE5F;~+e9mLdpZJ(8pR! zG=H+?fr`XnoOcfP4&<@&8TE14{Xa6ce?G};yVu_gR1&HzySt~tk{czy`0{_(7q=v zmQ;Li)cjGk8f)HY4E*P#v^!XU9VJZJTK?>dnzch-4P|4QVq)qcqlAXA+T>`7M9~rJ zyB`iNxSTf_x-&5JeBr;e<`*KO)$7dX{Dkjsd;p76e>HoyrV_ z;`tx>7h54c#M~@itX?WhgND6wKq6=bX79eVeTslI?>C$4N^nnV4eaycxuGgk)mQ6} zrdjJ!DgjE-o$sRSNYE^>`+}c_u&czmx^qTCc`AJ;Nz_I1b9J&|>L+S8w$-z|P6 zBl^d+SUhopAniQrsPa6@oi=(`9?w&MN_(JX)H-uY$#{sZSvh}_;}`R@P?`L*b3^KX z1AOg!9L3*q5>?q6GAck}cp&kGD8UcJH>ixA zWfOl4u`&Er`NEHGG%2sL_-9neyUW||XU_G-<{#J!rST>*s@h*tXg{^F01AU6^oH7) z2ff=GZ_N|RO=B$Zcn+&ZKe(AlBO!flgMZ$EIEO6IY#L*1u)m*Hb<4|<4A-{d)_Pl& z)_PAluJw4^t;p?2*F_`IA^ZH_pI3$;1cjIMc!jS?svPYXisT%al9RPbWz|qrc8N%; z?l0{wFD`yxXz~e5F|6h;#huSpWi_kX z)%~USWq(*$4qT~oQM$J2Ya59S84f$MDXLTFD=6p73{x+h(nnRhoi5GD(%|8^+6H8__GNy;Rbxr{Apy5PR**YHYJNN<;(G48^p>U%C?Ge>^Q7%xC)!p;03#G{?$PlJ{(t6L9U zRap6yW~qk$qI&7e_Qu(8(U5YwVmh_bO}s7>kvvtl-QhS4&W6QY`O?%qFC4S5vKQqv z^^u}K0AMqbmGT^`p2Fcw$+sJ3r8x#)wY0~|E_Zf^+c4 zUS3OZGF9Vj%NX@-A=@B3=r-+Ox2raMrP|cu>m?ZE#*;>yZb1{$=#^TyT(fL_ES7Gf zVi8vQ0;cnN*}P)8a9M@?H{U#W`lr3d&SWi}-;?RV_`+IkN>wG~ z)+I;wPidO%;uS9lb#7m)_$2KP7yEz{xsoXRwuedEPhT;a*8a^pyW$8s1(@YA)$L4g zFUW%D%f#*3yLIxo^~0(=v@1F)#7kdv^REN9FVB8sw~N=l;HLI?eTpf2t%S;@YyNE5 zf~ zuV_LmT{V)6#>}VvYFAg<9sfDG?of#?Vf$H$8g~#-zI4@xqfCvV{j5|C+w5ktRLTsD zF;SXkj8`(n_#D4%il`m0bc81es95^LhdKhUf*HTXbY-yo?bPh#0OQPaxmw^L&Aza1 z)8!0}*~<6ww?gmha^i9eG9U_{J2D=@atIpw1cz z7tAh5zO@Oj_Kxo@ACt?h`h$Hhqi<{pK6aiJH8XRlm(eZQ@2%K%lDN~Sq~5pI_X%l@ z=2F}9!lFU|w7D7SIq1=UgrHmIPt ztq9wGmf!yNxBs3~aqlx7Gd)+q8H%bU*`)8ZH9&j{IYQs!!kAspSb7-EAyUvXSnmy$ zQ?{2L@0o6K42_3{Ml~pjBW88~1miwJ zS-6lYel}H^fbC$P1H)PSd3<3~5Djl&dtqK-o@0f*5sAo>_BfN}4vkA~5WR%Rnl`sK zH((~AJ~F5w2wUY;SFSVBVZYiOY;`=2H6Uo#Ib}JzZ{Tx{ZdS*&r8n!0bG@_Q(jJuC zD+^Gi(FeS+s1};Qaw^RidKX~9+;mFTc~x4+{&`*FY}4*3!$4qyR%d$by#a4p1&mTo z>fFz)bJ~)PQU09k+)Zw!ZZ%43HrO#oQls=%nd19;N5QJr)W?|Ub0iK;aO75d)T=Jk zH?T#S+{V-(PY|-XsPDNDgc&a}YX_ib-e_Z99 z-+8E6Mo2A_;mA`vyeVXqwAD6Xh-;leJGM9B)FzE@(OA|d#g!LAr$ueZ3UZnL?T-B| zCB2+?cXHR=l;J(8qbsf|k8R^Q#{Dy}O^qGX>bnm#oJ5+bG1B7ncwiW#Lev2*bFIM3 z6lFDb?P-#PXlIHI+o5*+2*tkj1QCJYX2q;I|AsN$Ticjyx2-?OlE;mWu;MFa7ZW1)7*b5nLcbHtnH|iURsq*Ig*YZ86T1` z{>C=X%hL3L1m^f_s=zbcBC);F2L{37R8`mt#>UA_SwS6Y4iXuP*1Z8dB$8ey?*{%T z0~SJ4Y9eRf*hVkane6L;y4XIBpqiA(pY~_~d-oU5EQP7^<5)n6MnlrMq>eZ|y9Nw+ zm=rKrot)&q16gEi{;6HU+B2o7v!$?#FW)g6NMp7s*?nD#i@^fS&%gM{xzlXieR-4c z*Hy5H{)cn{M~1Eh3&pt%KDtVR+6z;!JW_0kcBZn!yL@RtJQ*+;8y0HDPGuq`wCj$o zWPM_3<5DTL@BXIk>%i|{Hob2#O;81Ve;6)vzm}EBo_+6B;R$wOjzV^;b5VtE($>6G zrcH?tTlL|aAa(=mS9x^%@VdLI#kVgu{qo^{lP{tHx-Y7B-`ihmzab!5B67jL-TbA4 zrnmXBn$ANxQi4{ee6!BVVnX=>;*^|MQt*SFP2yZgV03AUBJNAdkI*TLot{3+5_<`e z5}FMiI>APu#mu5K;E-?>zZtzxBf`Tbxnz-+{CO&lK)4_HbuW>YH$OL-Lknltu~P9} zEgnYTT($yt?P{E{Vr3HUBnsH26XN1?p{GUQb8co9N?7_%#e*PBfp!?P;q4H%l*zkd z@1C(bqec;u6)NXHLKr`ir1oYeTYUnxrpt7}9>eqKp}RU;ezpA~%TJX4Lo zo})KqlN+%`jm~_!fAxL3o$iGR%C_Xc*9$DqLym>k17ceR=9)3Ac>#wFS%JM*L5_=^ z@?Fcc!gG?gS_N817`stXKgt|~r6U0>4J9(BL|84pV5S3%q;`>4xy4Q@mTCnJW?2)! zvnO;R267NbCY# zd>p7!p%@?oN1IP3O(5nVp7RKgZ@o=PYVue z&v9t}fq&RW)OQO=pQ+Jy4P-G+a1%s3q0G?%Q*%bXKA9@=iy}7r&i27@>|g{XyLeZE z|NUO+Bn5V>McPl8Lam>GUvO641TFK3qegqfg@*>`6um3n%;(|=X?&5i-SHIfS-apC zVRz2YmF*fqBy#*FL)b1Nf-Ri^^jJ&@uJ6)b9fDI{8=|RG7=Z4ps=?E<-3R-(R18KW z#$>S{k_wtyTAo73GnB%;zNTnpkl9{r<;rPu%*dP34aVDpCKG6AR1zX59ir7aaW}d} zx4LGZbp&bc_FwbT&370&DS8SvWN6z83qKb!EMh~S@Iro>9HWqSUd*itXpl}lj6xE1 zo&hKREo)f_@O?{1Zv2E#imHIheL873sigXEagf|b3!RUOwC&|d0nsbwgrhtPh9Olc z&6Y5d7eikFJ%S>yuxNrCN}>(~+O2_U^m$2t9HK&Aw>xI0^p$2Vp3X-hoZa&wG?|Qw*m*O_35K}YrQy$ee>IWw}CJX8L_|q-HNXU z9P8XAx{3;;kk#T28qW59`RjG$1z*#-$xlVRe-EiL8O7n4A-Iw2wNdsWH^+c+88AEg zf`Z0r76d#CgcSR%5_hQ*|Dfc(Xt99=-g($CHUnrJIovJ5+KX(0Vi{st3YldeW>^_CK!}9#}cY%^YeSx(Sg>4cJ z@f&$|Nu?yFIr?~ibf3%`$ggi-nt%Kf0NY7KWvi@Ez0Azf?f8ovb!AQtquk(>v>#UA zy159@d*wZkgWJB6$^Xf0;mO$&wzjNG@~vp~inj4-T=D~8@a1* zR@b7iCf@pWM0SzIv5#Z|m7et@W1P2rEczbIH9~AAmwMeXllVr}j=XCW+9ZJIHqKVVFl#E%DT8gE`cCN@t zRk=EjnJkM}wGvR*yR#fx_5tI`uVn=}W-*@xh;uu8GH5Bfdk$A`gOJMv8w9vx58I%+3nm;@)FKJ3QZNkVmmfKiz4 zE$J!AR^367z4F_Tl@1MH^pAAiQA|D1eFWJ?4n4LjPD!=9<^i;9Gq?bv7(A~ylQu$D z7BObXWy&DKU1*1FW_I(vmD2HWE?E(ztlL*GhTEdBMxQicWfpE-(5%E;b_90Z`H6ax zMLx1$W`t{uJT7TJY6POEb9c3l?9 zj7f0%*L=Q(APwZ^-;O4C5|x_ZHjBaU{6!Hzk=`vSQv{~?OHS9-@0e|n=h{Y&Oqha_ zN}S3>x1u{$e&pd~Zp}6g88J4{W!UCDe+P6NNB{2n9&dI2;Of%rFy&W;k4k-U?lXn0 zUXKyJ5lo})HshVDMotf(U`C2H?}(%o=AN`5|2cuc;*0-$pgTLUm*GcAit42nUe&h{;X%ztuKODONk%2w1xu1CA!g_OTM8IBtI_Lcfx;ESllnJN_D3+JuD;mnCY1&a=34 zy2kgzBvdGLw<0Klw91z}udQjY?wHg4YI_ocRhC_j_}$klQ>r~*g6PeQ8f?@jCzG;x zip?SulS}Y6SQfYZlJgb*okqm+*WF)vOe2$#GM=0h`-Fp0Z$_ADQNcgv|6XWwU6wG_ zZmfE0iCc*tqy`grmnWrQXjh%CCwKdrrFM&(uy1d&@i`m`ngu4lYhmP9`u*XJ=AUKk zR87N1J=fdhl9w5ABHK#4bH7(A{0T;~iOl{%>%uCk8F<+nOD$_#GLqJkdX31h)%Brv z8*FjR(_PfaZTOiad{p3d*v--uOvyN#!LD5DWH}cmc)wLy&A`9wKJwI+d>o~u)W?AC1Do#wT&Ed6_Ln)bgOz?9@kf)xp9E<{?$?N-I3t6ikVsx#mJ@q zsqgi>;o$7|l5dHXV{W$faygCsH-2|Uh^OCj<G#&&{A zQatWyN^pp2M1MyKG_2Vfuhkd2*@$S#oP~`lh^KL6O@xWAKrCYuZcwUZE!(jgne? zHKUFh{I_>Y#T8blXF~F#Y zM*>ci=_RrG&p)WK%(C%>lA zZN9qOv8*0gog`JG&U1xK4=sq(=CnuoUR#0kHoFLDDWy)yugR^3J-%-wCmmpI1UJV*(O+c{Dg;eS{<*!2w{>;&FfWx>?9y$bxkSV2u&3H>gujgGi z81*=beDj_TpBTL6qR85?)Nzkjux{YUh^5|j3Jw61-)SI!LT8e*;v#tl{L2&7d$rv5J;%Z+;Op{cKc-#{<3>zy_D%CRlj6_pl^kQ2 z91dW-L7A|A&D;QuUJZFX2Lb8pgAFV_Iu+Cn_8&_9>~p;AV}i704rChbJ-y4E#_A2` zXc`UR2x*s+ksxAO?@gMy=6~;7b;slN#+&z_s*5u4Dr5_1^{$7kVZ47jY$33)gffdX z==5pcI=*&;Do5>8x5_Hn;8UfJ3_aP3PqfV%VLTs%u64s=Io^^E^0Oa}T?FdoFlqt@ zR9JdbD}8XJB0n2i#^=ZB`Fdt?Xj0nmZm8?!fLX`p21NFNa|hliBnxeOc2hR_VzZ*- zWIGAC>YjxTd;n!enNVM0@7s%|+cTLkZM+S>q((uI8P#MTr;PiH#6CB7rL^oTuJtdl@ z`t3qJ5MivyuWR)60%h2`v4QKi;DBFP^iJ%z`afkKm6k^=<^2Y}XONu^8YFVzL6zO zFR|^qg5UCAr*3>N3y9B?(16@o{F1&Z9nbm_)NwfOQ~W0c{21W_q}cW z+Vm21_vMZQ)*a)WLp*eE;l+l5*}Bi)c4=Sg$@(s{tX{swr~{4-fYz|rPW?-@}6W6NH0Okfm?9Y6K4U6cX{bwh84l7&^ISjo!5JVlB>ALLj1j0+=QT}r zS{YHv3s|Q4PG+X3q2Z8Kx#x2-St_j#5RhZX`+P|5d+trW>zXp>X<{rVSxYqOWY^Am zg2fc z10|l@gGD63{K{yTrIbVId6D*pv{uzjGfowC`2Akg>8}rHMDxgJ*rNWh zZq?r@S6S3K-v(sQo_%9Ysa*KuL+PkOcF&F?L8H`vx;xhxQ1Wf~Z4#{z!J5IuC*Eft zwhUS`eyUj6{2P8+8=s}0{TJuX9&ARNz~3dP`Q2&4WXFAvCgxQ-J@zskCI=D2riLpD z81(&uS(((=^XN8b4{Foe|LPML*>`bxN%a#ur`Mb4FDJ9h{LnDa{<{5APF<^c zqA)gLmuB;Ji`=M4G}WT~+Se7FTPaXPS|s2YamJe_^ebHRkPiI5eekZTt)@*vbtu8p zwk_sDSkHOR_;9GY8i0Jh5@d#(wTR(bTnACFB@ab;S)-s{tC7H?ZSt?TzVb;e69=jU zniJSm)k7OK-)=lWRnBg@lHewLym3cdhV{>>e(lPuZmaPn9fh&oHGVtr(9QmHBY#t& z{jn4ahtb8u@_w;Xf#bhURnN7e4hf56wzuDSsf6kkv-$cddug{NDfb%9pnp5RX2uvd zS7Qtuv*s8L1Ss+SPClC%;Ak!3-P>a>oBMcZC^dLF)cQ1lo1Kq+G>a9YP_(VI{Av zbL}8ZFE6yKXQm-}q5QK4P3MWF%!HcTg96B^f4^*9wgfwDeBuW?jx{9Jyl@+dWY%g~ zM2(hrwIECIjsdB16-_R7&i1d(%uKA#DOxj_Os>S5sy+_kJ3AitdmGNX}jS zUK`|Nr+=4^W?*zQ4qzMN{rGHDR1HmhDv^|M@v{-{_d~cgY1&I^5$0`Ss4hMy&`Yx{~RA}$4#ibf(|9_Y+q254{xH+Rhwf>Vs^1~-(&=jmM3RVPyq zOg&;bpXUFi3XI2lVmD*J{ZYYAC@*1^RG=0742CkkOOnwUzV0iJA>v zdJ&W#{|yIisK4n{G#qCzvPEt(!DF1Xn)9BiO=4CrAn(_^zGAbi3r)S;Gv(hSbU)e% zd0KW;%FcfGQ-OCsHo2tus>Oy9FP}Ojo4ytqn%#ZB+)Zs^H_%`CwV|xT%A4qk`5Aky zexL|4H}tJf+b?D4(%WWMU>AiM?vs~s=S_XBxYyzyCLL|wCyrQW%FP^97dGF|hlPV8 zWm47W?g^%WJ`YN+{F1LAfFC`jxAE+M|3s z-h)bPG?u-nYOydkn-gVCwm%t>zs4syl2_~ZVpMr@DgUQOcjt3?VIH4vu6NbagwCkR z7E*&gPWjJx2<}iJb=sd-PXZHFRO8QyvjT2Pf<@1g<;k2`UW8gg*iLj=L|UXmvkn>p zhEADjft+UG_E!t1f!=#dS|3`T$8*uRme&Jzbi@J3YDyn@3!DcFRol1R(Z?}alTZ>i z(Nemo%=2^tje&zDxz}=?yPs>CnzoX|Zh+s5$6`JT2TqVZ>Ez>9UnO&Dj4JP--K1n9 zx7w8BDR{SYZ+slH zsW9_Oyr!uxCQzpNvkE!Ue1Z4}PoxQA_nVq1sC{1rWZHt;$xVaD zdv5)4P2VEvU68j$G=1_uHUsT^Ay1`Nf!VZ%eH0|a_Z599P+!uYLiZEZySr4c_32a= zrNOJrL$Ecb&eWHMLG&PX3QO)=GJTa1^j@y9;brh7(I-@E*SP%7K_&= z+b7e#wxf=*Pf53c%|o>tAxbtBFdtvtSAJ}}Z=O-7(UrRrSV_Kw;<$tA zuQ^6WPcpIB6|8b;wR~a|xe9+IuICiKdY3ugBq;6vL4!I_FzuLe%8GHcQGBScgo(X3 zw#(%<$f3R>X+r&aa{gKtcY^#>iT1m@#<>Z0=ddwJeF$*Jg>GlBB1CETquJ`y1#z-C zJL_Sv`SP)N+RNK;%}CY4G_}xaD|>Fq4Hnt)CaD&mRYJc`i*RI%*vPJ#gS)!#&41X= z%lOuma(_?j#2uz^@nmMd)n#PcLCriU0HH|rp__9x2FP&x8mL-4hpm>n=c{&BUla}B z5}9Uplp>9vpUdMAIm$1-YlXnx-eks}+F#Ovhj=IC4`deB*%yt-urY-&`1HRSDfv~p zx?h_<8=X!TLOa~j!SJBr-rF$}{vf`oIIb6)nqpz6?O52#>Dl^)pnfe7&tO_&**nBC z^XSU`sY3y+Vj2C}JG;KnUIp= zU?@*m-`Ih#*-I-Q`vaIg#Y(#DhcP+JXZOt^3Md07>`4T^Pcux{FQx10ajo`tN+)IB zG?ch2f+-o9jm?>pW|DNrN*1S$R7SQw5jwx{mLO#6$~qiUc5US+TjgmKO}e>{rrV)B zd_#yGmgBS~5;&?RFnr2QnP{Y9n)j9QBbZX^YB&DbWu5M@Ybtr#6CdsVcLP3*7Ir9q z3*NizG9%J|31mpFqj z{$fY@viz1t1-#*R9;q!m&#wIghTo$>Kh)ZrGYlGuz2Oh+aj4D(c-=W@fsZC%Z#IF4 z)0sZsvBPeQO)r#0-ZYDn(fs&m3!u5 z4s{4tVlmafBkDT8n-4lTI#5@Ao6dLr+SOrgu3g#)z%w_DDfr`q;yX*~7yXL1b8WsF zl~^3pZnp5R4|Jq@(M6t-c5R;?K|YLt+i7~}X)n!oa*1u&_}|}7Q>ldw!8Vk_6z9na z>6ci=-?A{9YYutxttH(9Ph<0Mw(UUQ0@30!2V+H$<;T)rxqtKOyUO&Y$zKt@XKOKo z|K}uBvCZU{vO&+I&{ytbKfcJJKTtFuG$h`brsBN!%-8W(h#vg?A?LLqF>ATlYw+=W zn$OYnY2DZ3dETsp9;TuVJPd#T5&s5@`|gl``T0suZ@+!xzwi8dQB-L{Tiq_xVI#x1{dGJSDtNe~+PO1-Yzp^1;^4O54--k7ael6zyj!xlBkwq*I>H7XZ< zT+i98oxs!a(-SI~$oO_)K+}kUsx$ca11}FBa~$K;d##WF;ly@^(Ei#%G%uD$ zFCL9x{GrJfq2QoT?MBuU#X}O+o9$RrrY^=WS|zr4B`C;eV2aa;U;knN|St@%h@yB|SlmTy;`nWYn@ z6J_SGhi!D7*N!0vSdY32k3U`4wxIG1gz;WAZfaaV=*2+Ulo|(Ly6gZT9c6%r z-0UPXUK^l?49WaUdsjQuy>5~9*W#~Sa8s6oIZp?6xkt9@fm-f@pw%fR4 z2i9CpBA=Dc{yVt7mk?S3I~IOh6YNIA*wSS*`-JzT$gN@6(%~+MCue0yxZ;q@PiSfE zcLaUUUNSjS$C2fe)2`HC?=CfO?-+xXR~cH5lIoRC%+-~qzuv+>_3I!kDYiQ{S6v$) zx@|fX3B1P-ra!`sm;^6~280rW&2XOc1R1xX8rrfQ&x%P0BF(6tBNL??PCZZX-DW!W zmF`8gw0zSyYd9N%6lB@9vp;-WI7qO2jznfvsjMM=6wKn<-G9K&-g6-TSsT5xfaa#p zkR9TA6+)sOKE#7tCjCU+wtLXHOaVPO?jQ1zwEfCFnIJOsCi)njtIl+fW?Ew;IytFL^!! z2N*(Y7@o-j)f7;^q*o;^M@a}{*Fl!*?_vG_>QRrX()3@ReLf)JvE;yuluLeNYuJRG z&;5F!9%a#rH7ELV`iHhKCXhK%0LzwI9ND>)g|Z-VsWACp+&}7&`R6^WufQ@xxu~HF zCWa(fzd|kq!NHipWVV?zT%4UFtNrFw7(xx*))HfPKhJPGZ^fKY&PTi^-mG{~UHSNx zkF9=Rz!bfG-El|CjD5w8w}Q_s1+ld%Uma{heIEg~!V8O$JJ+(qul zN^@&-G&8elyQYxK6Xt7xsa~;)d|T@Csl3Jy4Jbu20B+TcFZ|}@)WkMH7V=F}#tv_{ zS90LpfVtEm#=(mH*r)LmYI}=%?w2i5Qp2LJ2()_>*q&KVr5E`3Z2cNq)7uxbdcGL@ zkJ5m(!0%)}m*-8hHxWe{zkWA$%k$@ED0a`*!wq1EVX!QAm}oG&AB8kOnG7yL$~g~8 zq_CpUIwN=?_6ha79DVB@4b-TA*`biqG#M(a+s6C)`==|+1(BhnU7o&~=UXNrvSvU$ z)k(q$E&H`S9s~O|Fsf~954Z=+AePhhhL2ejq&i0MZT+k#C+F?h#!Ty5F)Iqxgac6H zM>n~;Bt@qPo#@_+8G zEl`_|uj2j-#`6l|)D5H44G{P8MY%YNo9|}(2R`G@RkJ3n5GYwdYa{*1DCK=n?V&xY z))UgskQR<^u#_8DWjN*aJS%xR`DS{uET5_Jm%U8Axcz@LmGvbMZ?MK5>Aw2K2cU$0@_6gvK_Gvj9@m6<smdcCM9pKIviUfx1SIxOY_qVDrDxEzb^PNsB({y z6S6@F61BG!x^XJ}zjs(jd6wShlCE5?`>K378k z?j(=6!$A+B_1pa=BG#P01(Ra1EY5QEub9NPk|(e9?-kg}{?xGTM=9PPF-UA)87-7d zI2`jm=J@ScjK5TC2qRlZFUcyABp?`1f!LgrBmQHk`}n(l&FE&_?TNVf3(L2>TbunX zd3=)MwBye{H;KgACxotLL3VVa&!{#6!E`6$DWv0AarP|Su#=jW6TJOs8=~=sp@tw+ zgOd~8IIXX;XMo5c3}T6dyaR78`6xR1P@+jml1X;SMMa;)Hx3(}9#3yv*d{-FoPJyi zzmro^zo9OvW#+#xy-u0q2|~V5Xp%rS_qEF34d5dUL}#!Gejyxi!7BPZFkJz&8;spR z73)Sv^GA>5xQRfx1ywUuv-pN6r^~p~jnSVtw3XklFB8vcR+qdwFFm|zwpg=Cb;r_? zE$4-0{BHCgVDV0X+y>ym_EIJ2eX0)v*~RX zX6YC4SU&e-d-X-5v^X-rNKF&Ee=_aeSnfl&Qa@q{_p2Zw+q_5L!|RWiu?tcds~A%yNj%5TfaqmjW)mJl4%KDGkj zl_mQN)u3*d98!}vo3|%%?3Z~piCTSBQ(1;E*`yWa0w3S&S5GwAVCh;qz8{r$^pG7l z)_Rde*Y3r3lL)uQ4HG3{9z2RTp>2>n8ZT#>VR3#OHs@`IrUeLFqEHl}fD@-iy zDpP5`Q7zk|-lI{vTfg$H;rt~Yjpn&k@*jP+<@R>{G^bM0=hq)}xnShr!7yaVG3&)q z_axIb&fq4Pr~WT@yN87w)`-p(@IsTHq?-=ocrOH_H4BaZN<9qe0*!AgaUs<kv%{E;22@r&2^A(E1$u}8{bL>Yk3?a|!pz6B%nOPE(~@;Z#D z_+&fVq8Ie0FF#1;a=)4ZJ5KAgWBv(R;xS8F|Eg9kgS_(d<;s%lo?qV+T^jZTG5*>O zx5PH~b?Kc%Pc{;{dV(YY_)iG21!rK5X8@;v0NwiWd=z(zxR+?!7vVto1uQz5WTy>hxp25T5`RG?B8H6A^C*(;U` zif_rRuD_@kn=V3vZ;;G^GAOl5|EPCe@lWYRHHFq+xr z8n2X-F#e~I*pEPhYIZO*d<}j>CRiv-JK{9X8f<#DzsF;Bd4AJ;8+;tWngc|MO+T?) zwcgBf+?;w|O&`viIWs2hWZ!P-NWiH9|FXec5Ph?iMiF@Kvl>pKqI#nU7tuH5-YbkQ zok%Q^zHFK96LV$95wwnZDp&0euV4(31k;yo z(|mnP?JjNKnzkp!og5ju>5NKx=?gS(B>YH%M7UozqFxL*h~8PYdH798Mym2T-P_bs zsR^Fgjv#}ZtuKYX`1QQVJ$^12Rtx+U{k`EB!w5LCcc)ib-?1qL#hH00M0yO}N`=9H zNRKrePd^QTj#zQQ8WeZWUffF{AC2^3VqYmW&Pt{F-mzMQz7J1&rzNRL@&D*Lr|3Ys z?#*`x9ox2TCmq|iZ95g)HaoV}v2EK{$LP-V`@R2JGv8V>>(o_U)J;9L_dfg7et!It zYJXTYUuZR7cr{O=O!g)YD*RXIm86`rf!8B zqXZdyO~4%GgDPh@f+$QUHbfuxYFu>)*Ck{6Oss#%C8dRdA7^xR&=>1qM(e;STK{f4 zmh2&|U85HK8Y4j$LH6Dp8xm3tNPNTUTUeNZ8%?ln1KV4C9&COS#TSmKJ_Oonm*v>* z4RW<{_C_SY2By+Tdria*Hmfhz^nT6J28t&aZ(Pnmya6TW)m?ycp9wz=MZ5Rz351h& zL$TPaPWY9)8%wn;nC?h>m80w$t}5OBXk_<`Ks4H|@v9>zVN$tJ<)6E;w``eAHi26L zgYap2iDP|g8y;8U^K;1$lMSWmmMazg#U=h|#p?`UZXcvk^r8i{bf4BIQ~LRRz1$Jz znhNsS{6huj`fH0QRaMpckVCHnkiHZQzVx;LOp9r)1wla=$BAu|qdW z2n^zB$Okdbsns9_%2-ZSm=4)$pBH_F7+4oGqDGe+M*5{)+y_f4;@FTxaKtJ7UK+Xb z_6M_wJJ)BsEd+xY<)YnNR~2N)22WokN|ii7u*}gXg+8Y>K))WVQZo$;nAh@+}5Ze>8&c*`( zauqGsX)FZIEZIj;AGDjLV<=n?c;qSnKKkvP?;)Q>lO|V3vkd|3u|C* zC%85C-G|^+an>Ebn&(r<5Llzi#ef)v#t{2yt<180!1jYdv`>C{(@$eIeCwHlhaJMK z5<$ufC0C5freIkZp!E_z-f7897)cHAfj#*>qL`8Ae|IU#nal?s)>yhn`9z!f^TdG9 z8(&M&$}suf@si9Vt1Fu5g65XX8%}opLg@{~(I7g&ytuH^0rwj>P4R^Qn4XyYg%wp+ zZFcu7wCgGM#$6WJvAaQj{VP8DnGIq{TnDs3FDcEUp(x+C8?nwGqo=>Lswj#8)yv6? zm&dgZUDFG<=EbY}+>YPm=TG`hr%!MnV&bj9+3AyP__di|RLr&SVLV77S{cs)ZDl=V z6dQ9r^8$5F5k8w{wcAF9@7T0T5;YV?2Ii_ov5^Fn+nh(3My0h_d|*S*!HXY3^#erN z%cuX`WuApSe{lIFN%{!Cqo_GRgG;Vvpx{KqtOyD7TKi&aa=;Ybjz^*jj+Hxj)0+r= zdOkLd%!pu)Zlsp9W%%X&EBWb%Txt`EJJG%S{T2Itt&z6YSKS~VxzU!A_qAmgq4CW9 z+K5;S^7X`!?99d_)VVt{`e169W(NO>2zSu{}tZB-FkBOmEVOz)kEc?0yJiXjUD;O~B++FxgLac(ai^k+ezrg!P{! zS!?hnZWKF5eV5UjlhYE$fLqDHrA*iwsLmw51ryIi(%PTV%P%Hwgv>mU8F{ZVe(ec z7-(1BYCQ3z+(oVjx@!{{^|-A*_~E+XC1p#+>M~l@5w)a3+G#>HZk?a#K0erD(+dUB zGyYQi3&n(IzkJn(fmM_jXG~XT8`~qR(ObB~p1m28sFX67o+F0U>AJH;V6OhDN7&A9 zM!%t*Ya~~vgcw7*fmM{dSK74c_$L`cqFJ6WFSve~R|Dd~Sx`adN~c*tIXr=KLYx4h z?vg==QXBo%3kkADpMDF}rh)ZHuhb7iEH_}_9M9%;fBd{2=vqFUus9tn zs_`Q@%_p!hk7qlb(BG>q#PlX6s=ZrDfP?wO3ICM;n8|=)P{p$$o2#SlgKs|ko)xLW z!*)2%VZd7OD@g&Kf}}y27hSI|SmY-a=ts|OtBr{E<%bL$u~v-7GG~{dXZgFK42AXu zulc=O-M}F^kQV(DRSbe!0MwHQW!TZ3b#L6B_*bj#GuRM6e7Q$hkF~O6Xjd>NRyikb zJzj!=IJv7(SLysC>5u?d6W(PR*nMeuLOGwyimJ<^^h*dMwC*FdAC%l|T1R;1B_bPE zgcpOT3Ka6A`k&V5kn^wMemT;#Vx|x-E&W57=j-p`YYE4^h zmjGv}7c*=OVV&S75?DP#nFmf~_<`!V)r9@SwiG(*Fs>Y9R#aMt5%hsDJq0Z)B5@~SyZBJna;isH=U;d| zv8<%$6P)naqy3rh^S61r{!7&+jZNZgzJO;9_y*s6zWTRf(8`cQ7YdroG%$>mBSy_> z(wvLHLzFE{lwr%!t1JkPqhE4spbP?wN~utZb&gJ5=UFYuv1tUU{M$)$Ii5zs7e+x2 zGun=|J0VXW;vm`3&JVG772$w6nFc0)awnca(o)JICXq1<>ZD4zK(Aj9ysCc)gi}}o zW7QO&Llm_VswX?bDbqcv8PS%M@%AsRso#^4Rz)$j8ri5qDjHBDT?X|Sn^CQznhmT{ zlwe9S$@sO{=~Uf&UmJ7<=$akQX&(9Df{wuI(I_C*w0D)p0>WpiHnW4|2-Rchj6NR)+`b()LK7RQvIX4ii-iR0Yozyq(RY@o} zr@)**0T{Q2yfLyUFrMbcQ-9Is5c)46o)D>_hT7qH{?P4cEo1Lfx7MBj6o1k)!75ls zqP+nkad~gw+Ay}yAph&N zR^t|3kpXOkOSizE#EC{UtdJYS&}q5e2IKEK@$+!uIHKeJv#B25fop~*(j^k0i3X*r z6k)#A>@6x62Bo#ss@3Y|KlILwrCq()*o`gW`5yT{zBi>bI>6_~C~xDg0P~xu=C|?* z^f*am6QIS&?QW5@2{@(W$WU_M2`JUu3JubtgFr-w67@`GkNvVDJX>f=i@Z|}%+2Jq zQFOP{>G5>q$vR8xNM+dr7t!)4MjM$0W5>RDTFS+PM;ZoI$aqL|5xtqeN)rn#ir85EGz_A;?nkaA@)< z`N-zFl8JHF3@QEAPYv@a^w~Tl0&~(NIo*GWXh?tCA(WO>#AHrRdQUZ>EFDEwEFdn~ zma30A^W*6#lQQDYyL?bq(4f9H#n^-`!E;r}JnCO6HiGD+WW&;&0Ce*T)qi2V@#GCS zJQdR1*0Lf2G)G?gMim7`9Mmrw3?d(iwI#Fw`)zNh1 znUy3+?+<|gG8EqJz&H8(?<1>e_qwcWV-EKQZMB^VyWvmwI_(?do^zAdy&HYB3!c@h z=XxH>9|kqHBq;g*pZIu3X$Az@Gb$l1{f?%|%vy;9Yh9eD*Pv3?6*95Ei3#}IleXfT zZ0BRqvYJ7zbgq!EcqvuGXU+3_oCv*Y8V?@{j|>bHlD$k58Z`dsQPqmiDmM$^6{)Qk zOP-r_szlAy#d53bsjthcS6W}rBb_I>l}o~{7Q@M1)Pdevls1h~;hiMQxoCaJ@Ga5n z*8I`g|0%0?^CIwHUJ9-58d?YhQ2)3p zl{Kjb!PKOA1$k9|Q_yl;MBpL9l_r$s9)p_5QxM=h@WA_hY;F!_?y`8(`DtmsljLHF zF;bBsx$Qjt{_~k)O#jp81$LLyENL~k9#sW5sdDG&zyrC6Goc?oTg8DoATV%&iqw%j zq>;09_h&M208NgHil(FBz!bu-qvW93hZfq#_(2xB)p54WD&WAn1IL?W9Z+X;RZ(w~ zjs}8?*&(y>_{s~~DU4HZ@G49K%j3FIX%&ThV$H&P8^e`_v8A=u&`wb;ryWZ+O-;%4 z!2TG!OA{za#|8f!*|PV(X0VTa)NGUs4)P-pQ@|o>=ZX#Xy@f=x5%!x1Q z@0Qql`1mylj@(zf(7?<%RfKfDg+ie>TuF3ZX>${o&4{v+(0F|fy9s6p5@pdW{5=LN zpCaM>!RT^K{{0r--?FZTZh_nY_n_KK=&Pj4Xd?z|DQPttp}DlyohkIo}`xkuTan;w2vU%4~`vbHpkI=}P?k{T@|sTOP2fGH+@qoSg9i*1hr|lRPvr#J2R=z-=~Pc!${3IzxZ3mM4Y_7NDjw_2J4geto)C;6PO z+n=X5JM;Vqe83zCW`rOOxWNRB2Ea%Io204Jl^v1<*Y-0>s`~k~**oF`%FUXR3*rXW`z1?KoP1M@# zDgXwHtdx`rJ4l+80?2?SyK}ivL-K7^0k+Pu-HCBxQGLx@Sym;?8UbF zF}kg0ocx)!Wn1vpQA6ED8w{IprfAlLryrQ9&hykuMH^NV<$kz4g~%5_1Wl>5SjJVJ z8!$gIiEO1>1+G&iQg@Tb;#=sNoLE2xz5`k;*sW;e6Pd*kXj?<#ab{dM--!NX*5#;L z@<7{#IetrE{ChG$)InQp%!6LrjXd2#yPog`y|4`jtGA01ePGc7p8k#F2& z{MA9C1l_P$%eOS(aO8qdUXBOykOY`vx|>HVGiv%`660R8A|n^;hSu?Gfkqrc)cM9a zr*;z|{Fb`3cL1J@UD2oacz3Uc9RpY~>5U2tQXcjTbjf$W?(ju8{JvG#pD#EFqyT$C zxtVik4I{YSGtctxA=(`{x=sLG!+HH_!eUo`q7Zuc`|aZSyyMrC-G=PzJc^1?L|oP= zCu5vmkQ8`=feJ>)vq`1qxfwT^-J;5$x|v}Y)FwT_4Klq${I`TJiXT8q{(4`TeEaf6 zAkE%eiz5xb^B)UOKP?y_72GN$P_*8tvRD=UW51}GKVNJrPz?5F;;Dp|zH{n&c{d9f z17m$N@L{6vTS(Xa1W(gN3KpQ9RQIId} zl4zJ}v}0ED&M3Vcfq23t@z2<=yLBN zpMHHLIr=-}bi<8f?FgUg(W<8<)($-M)oZ{)T*kT!`AVGZ=8o89&St>UGGPxGq3=3! z<5eD2?ms;HMmuU@cSbVOq`Tv!g+sjRnnnHDtOhxd1@t52*5wAOq8X zfHuzL=Hvu+M7~>;wS`Ob4uZyk5IJ`+2cHYfIz~aDQjp4OV}2M7PBe(KnBO9zHdbCpLe#lMh_gQY3u-0siRkH;RpvLCw zO`savCIi8TD`e<++xsnI9dVQ6uDw!jK4H+-ctmSf9Qcwa3Zq|de*`-JJm#{=b_~5p zHFe2d*;9ZO`1;>chRG6ObNOpACCy4<*&cD1C=u{K6EG@SSjt&IWacE# zt#6w5d%v=3UiW^yiR$?(bD;N?Y}FIicpTO|@&(sC<`C79K4m&<4`c)b{LpcZwi}mh zqawiy7ua!_bnux_=pf;#*MKq64bkFXhFuoI952HU=S*c1c7)ljKnLw%;H@sCz*VQsQ1tSk*{;3$Pk4rnQURRig^qAZar$2tb1&*kc@c;KyT*ex`;BEq^9F ze#tGEw`XF;z3P)KkNZ(tSYnfD#Z;DDOeDL7w^}cFLnKG$fTHxVSJ`32~3MGH)clxl{qxUOtYryL! z;8(hscNF!mrYdV1`duAK+0v?x+oK3LrfA*FruIU1W3htO$P0eZwS`wQ~e zEb^#J54|Of@YwW^->5+|Od@%WrNAh!cxrH;tOLv8W!mUYb6!DR#D2>JlgXIrH_y}| z%7euzCrop6Y8zTd`{F^}XRhpzowGX;&_jJhNMO&O$P~(wU9qdAOpYv8t|)ObiBaDH z2P-=Mj~(A3hJw7N<}^n^mznjLklbW&D|4u;%#^95%zIT@(u zHEjpopw~26Ml>SdMIT-w2i-^tbgbb3Jb zYQcglMCtm0ImQt@8?_RcuA=1c`TA|fL40WV^ZD@t;a$9?5~oHr4OSc|viCXCJ=enh4Dk;+qN0lXxUUNyhCt zk~bYd@s16ekjU3l$V+pQ?qNaAK%?F)?zhaNEnv$I%)xVm{9+%Ntr|`@+Q_6+;4DOB zF9Ig;%2n{elfLiY#hWb=*s zow_(;sl-@O9cj11m)T~~^}Fm&<$`)Q&m%n8azH#|%s2wj!d!)|o=Q_Ys)x%U98B9iE;%$fNRPTFvP&->a{gE#Uq1GEs zu=&1@xuH%N&i=HUxJyoq4{`@H<+V9?mmCs81a2j z);DT8jMLtTta{(qrR^&7%7)EWy#Jng*&rx7%P}e#!{leU8WzJI8dmK-8&vIt2WU0& zcJdv1ZIeOPcdjB_nUX?D^}=t0XVmIhfY@_V^SbHJskfVaRRhBc{vEle8d;`fO8wcP zv&hh9l^R^?9+z_Ux5po`#f~&(Ql*RH7)(%0xC@*3ga^7mDfWD^#2r)&u2eTWB9rY% z4lw!S=ltQ2`49WVnfZ@d@dqeCaLfZU*PBUw#uf4;U$S2@kh@L(qy*Py5TrQ-0NR1bzGXg)CqGMzKv+7m2Z)Z`nEtCR|u2-{N-|y9j?Gaq@b2*W@8E)@|(R0lxM0-bAYGonEM z(0B_nd9hkLo|05?0^eu7*Js|aTy)+ zC82qIvfg_H%TP3ufp_BX8%o&9l(|vW<~=?=z&VM<%94W_B`8f@HiuUrcJ^+ksgk}Y zO1w%_c5SgmkUpE}LI>fPNBE!;{7_4Ds>9~rw|2l8vzByy-j25m`rZ-6O!y~)O_u5~$&oHlLfg+~amN^Ix)A!L4jBsioHx@EiRYGt`wr!4-(18I>YHDI zfMMDlWxE?>&)mr7ja|pjWL&utYm(o;i2f9t2FR{nnuf?h+o=u3)6_BWyYHkVCr8aC z!>|@clo868guEC_K?1j}rVUcu5sj&n5j9=@=eU>H(sI4J?Tz^EH62!He zCxsdk!u(e-NxcXV?p;EmK@7y6h!^w@dF}Fj1QcNHhJbr z1L?~bqJQc(eBfW3-M{AT-Z(>8ej}+(Ek7f4DaaM!6?&-}P{b9KoL1ow{|?mS3Lgfq zHx*wjX>EHnS6^$CogKIniAgW3T;17 z#6LY#1=0xPn4PrXj8}(>x?i_9s5s~eZinl8OFEa9r-Xa2q2NFii>IM-8@+gE1Cg6_ zIU~K#f%=nh)_0xKbG^wln!Ckb=N5c1sl~RfDD~Jglme0Gx~-;>a5fi9fT)hdSuSg3 zo($M&nomud$#Ub*F|=+Q0LkhSo#B9v>zw|X!J-q;$=snV;Z4SK#S?q)>RR(<#mlvz#Rz<=BZNBw*R(r86s|5RT0L1tpV%;#Q6t^0yF{9@IIB z3HE}GY|SY3{y<4;E8Yx;Yea^j`YDkeh3`O$89OgW9TRVdnbn`s(ad&f6({R#R0*I3 zIw+hoWpQnNRGs-W#pikslz?pv2$dcxhb%TdfJoooA~qj$X;4V^^ximU)1g&cz6(Id zkAr0!H1v7PE_fHbF2N42m&@E)33t_}0nKXYE}4n39O^X%XQ1|w?3)l0v8O855^b5Q zvkR#ey~L5(j78d_wm4GaeX%Pf4)D=>25VJ*YBu5KJyW=@?Aq1eOKxaLoFA2)*~r?4R|mGLetf&3^iUu2 zeyQ&5#^JOlQ|VD=3I?UV7L)3Gr-nZO4d}vIkEP}xOzh36UQxq-<8${GWU)m9dI?lN zpaAsMHId{+@+_ge^j2l$r%i@UrI@&#lKf{E2*P%BRdmm{spa7X zUA;MG)2i+PMPfDucWZO&AA8JRL;+*=7U1nYYbMe|g$KX(V?!2rFO)7QGb&cPrN$g^ zfj<2+)1iQl=;ABe%8!a`Ii+>a3FyuGNPgu8*LL;!dA14I>)ae`SRjr&RrD%$LR$1O z=U2QD$Uu3?I<|~rnv(eqt?6@M1sC48wzV@04fg$4k+It(ck5ktubAB znomoZH}$*79duPrSvXbF{sN;}6oamr)fsj?mKxG(Sfqihy#&PBc+9c%fKjfW?75F% zrmr5(gR>^iYXQxRic<{@GA@NqDPQa;bH_Ei=m`>iyvIvzl4s=9FfOm+SGYFVHE;bz z1!s3=fbB=YyhrE_w?B)drg6c<>B|1!`QyhNewh32j)XoSln_G4xDz|#E`5@Js) z=#H>k>x`6@4#!tTPQ+~wy=G5UfuJueeP)>h^4%MJDS5CY2ODTsozS!)P?)?V%-_jT z>PC!nvym<0dk0eJ!Us~UBMM`Sd(xf{C=}< z6vABuSucDuo@uond5fOY42-?z4j?o8mb?(4Gf8hCdc)ElcsoWBFH&D7&KMu4X{9+M z_r6q+Meo9V4VMmn4>0(edQ0e?kpGP6t+?(DI@0dIWVIEe$SZT$E%7EeFN7DT;+kD{ z&Z)R`2Uw_%_?>f(t#!`+5#TPOTrJvV0@qiHFaH=KLbX8;o6uwyJCRp)Hqzf^pWX6) zhrVtL&P5|-Fzl3pQcOdZS2$(8ii4oWKhYo;NA=B~V%Bt<168n$X7P5QXm_u_LZ~|@ zal$)<2FN-8z>g3dFw+wUl#W|Ip$)&P`oPJ5!v9T?|5t`=RZi5>{g+)Z*Q{mxFR?(d zO^XHfKL+~llUh4a|6!o;zU(i1rqOL`F#=mk3*RyMq_ava0|~=5{J;ST#R%v^^bwr+ z1UWSEdKQngCZr(Cc}cCjzL7baZy9%AeJDp7vkLXThv{AV^_b7NyJhM303Tqtm`lh~ zZKnI|sWPi&qo$f8ImoP=OOCZ*cr@I&c+cR_Gl7(+{1~HaDWTu}SnOUwNFE7)=>yN} zxp|lEdZVKne0Cj%1F|4z&q1%(rG#kdwIgEz&ZmBkS>+3ENi$us_scQxA8CH8cS&$x z=@M#sTXgM*Z7Hrq<*=U=4Co#?0dCW3;LZ4St(px+v{HEljT) ze)~JrfjpucFdniuN_5o$!xnSX5rm^SHjb5fI$t5Y45hw-$Wr(*inTEo0a_bWAk;F=)FXKJoz6CmcnO@Z{ z8*eW2))zqMK?Z#5E**antu{k5xCHOX%q|3*-CT}hbQvOaBn!4nfxu7qP2$k&HUFxx$4I_Y-&ma^F7#`U%Li-oWjRb+8VKD zKoKg}Ag6pD2})Q7b$d7A$Tv-?WrC$P{2BwHn5#W%@+DIInz?bLJ<##=eb|H5AyzZa zN8A=h=_mrUs`)H))fD}li)gIDyyAEk5xd(%Q8QWMZG}y{KmXbFL;Ztkg#7Xk0wwcO zYvw;-zt*5Nt%85WYxAL14*wtK115}i8Tfz55d(-U z8Q@S~zL5TX;{OvisA6wzYNz7qVES*>7^9-Cj-rnGM@;CL6n2a=@=>a57Fr`3W05*M zI9`I3)RNqw$o35J8!Rb{CB4Sw@9p(>Yd|QEwWWEY#_e?;0}%RW5da+>&xYuQrc1vV zcb=~{*50#a@jrZTIKG(Q+J50j4N4EICN44}3U}5xoMC%P1`Ac8g`$O!Oj%Pw;$+xm zbOjd!tB}!0X(LoH*22I@yI!=_%5^iZGi)97<}90E%m$3u5HN; zBq`Xo>055EXuxxZA0fafgu9RXSW8(0hOKnKa;D<-9#F`U2iCK}F z6S^gIvpIQYX6ynkL=C^E*=MAx-MTAynAiIs@ivCz>4m;Mm9hGTsqt*x32kT7hO!1Z zGr>NCo1V^dZzsT%mbpXv~($ zM!nFiDUC{veVwUP*VSs@IDtAa)UYC?%}|=XiiqZ(nX*SA%PyoESh7)tb|n&F4qg2o z>y#PF`nhAu>Jw3m>hkH%1?TBgy~o@=7Y{;bhA^_RXaY3biH|>?? zY*dSxws7dh#Q9BH(|(U_R3*}UtahbktUA!PNV6?%9X_#8iLijeoWDPvhAvgb(4dxf zwRB+@a}LOkhSH8W;;0oJa$_gjK=CzIZ7q^zEW4!QJ#&N0j^~T(%j*SPtj6^KW_Dxr z?59U^wwu|QJIk|X8^0}7$2aQNx}T<^@k@6~oF4|Pqp$ZVzCg}+bMEhfBZ%`wdvP8c zP7XLC9N?4l{yg0a4wFP+@Z=l|r~4`3-<|aw=K}D6jP8R|jwWzRi~@b=$$520{OfiJ zN(S>Q48FK|BTX0r5|69ctUkX5ihlF^v>syN9GIV0R*P2W$oj2|zBz?JHO*})h#AY)N;Fj!T5j+H(~X4p0%x4q1fHAAE;^|pZptV{|&SMgi7lpIkD}(aIK=hCm;g< zzfh_CKZMr*giL1zCwn(b6H_PB|GND@h#Npj*BV6-l`qN0Ez8AtWx1@rIwo`2Bxsl; zA(8?7OsGsq_!fseiz%aHEoIBL@AH7*))2|(7UHF7(0k-3Dl{_2@g|G&$)-0wPmkZ{ z3)C*tn`%{osxX>+`j%`6ah6JH(@?JR4P?4xw|cM>n&Cqd>>ym~(R@KwkBN*n}%ekF%CW6qpm z;ZR3jRZ8@-lzaJ=B|y=g%oGvq(+Tron04Bax!93Cl=bm$&8TobAzQ?yflEdRE5@|K zvxm3I12*6-qy)qcafF&L+9Z`qiU6qEZ}QzsC$GsNHMcCwwYF>XZ9gT#z|i1P)AUO= zX%EVcs$6xc2j3BeyP($zwn{ssB(4x9f$a+YtdU?5mQZHYrGF(UI@6NPUt+Q%t z{i0>#y=KFXp|iTnMjOL==YHytUzl7f_vG`KZ|5lcKIbO;UN<-UhBl)8QeMjlnMr8NFp!*%4=x52$bI!}xKe|x_S}%%FVtXTUIw5(eds-Av z`=z2Unn-@vgTStU^y+WfqkBM~Y&A$<cBB z;V}@=5G@TUbSml+Y$c(P!825CF|NBG$yQA3i48_rBu8W##Kuvk*?@`#lU@`{Q+mE= zF*-_f`i~(Kx)KY=5_EG*rlmy7ai9a4C0mJ%CF-stdrCB3GgXDhv}Lgjy;+MTj6A75 za=KuyiHOuyE`#EPntLV@!D8iAE4y|GgpPi8KPXklVoXR-kQpDE3@j-#us*g!M7@a~ z=^_$B*j0DT;m34s3=jnt>p`1}I*Gq239-^{jF+<~L5LMAsxCeti8nwrlv6LFaWU#+ zCU$K5t@Xj>AU#lmvtnFkjIuN$rV=FQ(j1&4EKpn6afuRrM+E~~tUo70L6>xn3y|JQ z6`{qxfn9C~oim`^mvcQT>pwhpD74BosKII?tD{4dStJv}0|G3VWfoJ#{;V!5u+AaJ z*}}Azep?RXs*M8kt`uiwKB!VZH2?_fT_v2=jE{Lo)~wr9t~I&RmLxZTp9uMu_V@UcA`KuVTc69og0y zpJ)sb5|kZO?V3vm27QZrs|(zC^-s6M4wQ0F@UDt#;2aS90R~EN?0)%%T;#T!ilEV? z8f+5HZ%7$#-yaL3RBBspODqW2&`PTY4F>vp^h#}SYv z=H};;zpZv8DC-m%nT%OWoHYfBvBDRCU&4yh3-xSO0_F%4zGUy^VC>|JIEewfYUGRu zc&W4vz>n?3p;R4{F=T0a^g%I;-sjdqD_?JA%JzzxcJo}J0Q{&aGuWd>Nk$Uy6a3ul zq9~=7kcUAL%@ZdNhg_iUjqI^y>j z)b4S@1ozcF1JgZ+Icfk+qfiOkN(KVg4_G6jHpgHkx%X`KXhP(vwqrQ$(>PF#;z}@C zfW+z0aLqJg2$r9TmPX#r4L^0JL5Jm~F54~lSKAyq?5StF-)&%yn)~d6p5%G=BIdGx zUb5#d7q!1RnLcHL4!$%go#V#oARGJsyg|fBs@UE7YPc*rJBiH%w5FvoOpDgM$prP? zT6q3|7%G!=rmbayw2ftoG#Ey=`J<{EkVWUGX*+@4t|G6jo70hl2IeYD*FKrrJZ~_; z-M*Phb10=}d`m@y?72S2xR-mJA?k3{?93`ei=(_D|lh1JKyJ;&~Uh~mcsMR(o z9vj?V>%jSdY5TFD7G6?s8(=d+ew8!0cJ)_X;>c}e492ahG=9Bl?efoHb??yU;mBAI zIUa%9oSq*!v6cBVFw=m1nqsc1Go)ePq4Hy48k{>Py3D9s6rv2*(OT}G+zHpfv^?dV z36Gf@mXfsRh40M68L|X_c4^A+0vtV|%9e3NOqb0`N(vm3F-k4|Lf&&m{(AB~H|=pS zfKGVT;EZX|CNj!{l=GWieRI)cJv_7QeOKYSVG7Dk0&A>bLBM{yW~CWP!z4F^mg*6{ zn`Kn#%@3=PEVVeMqMxFDlo_CreT-bAv7l62aP8zSV*N}3Z3*kC z&vlU=Gm8AoE!VmO1PSmZy4;!R;_9XKkyQ_`wDy`Azl)K2rIu0+rR-5D-9U>|R^gs( zsM79%>82O9pQOWUSU|Ys=SegFBE8c86HI2hq2kOrpI%FU_x3uz_&s0SR7!|ih=sg} z=vupkzxoEA&sCGbA8QA;QBF`-#`Zd*<=Ii~Na?k>!^^|Fm;hj}TIx>eK9=?sp`(A6 zT49dMUp>(}vLunbynRut-RHltb82p$tJUS#Z`?V0W`AFPUum&0ubsKEv}Mf^w>){g zHq+1AIl70*4%Iu-Y+hWD!jI9DR|ZvGMEu zj>K>CMStii->!D|5C3aEF3qb}uK3%K77AH<-BNqQP)zllJ4|kOQth4gKrU6=mC&TV zDH*o%>SC!^)eP`zDFzGG87QH6_x3dGq5Z2p3qm7SVt|jt8~g0pMrF0Z%Q9)D`sRb{ zVI{&Il7eRv-JrS2Yo+bu97ad8XXNVHK^EHgA(5>kx~5nMCoSub!fHv)0ej7^Gn=DD zQ0ZKAM}(~C<$>!vj`nCsm#?i}oR`8}<}o?^9NI#@t7uWZ3E|Q8J;Wh1Uno518-!Qq z@?*?=6R@yrY5CZuD>l{`+OGGbkXAQgeV^sJAC$qNTtUV)&#gj1Mj+~Z@~sC+mh0$< zYN>~Aa}JA%TJskt3IB?0`bd_IE)&`nzT!8mjU><~Xi=!~$hw>aXeIDqEYJyu?6jM?QmiE0S-%kR0(z z#5sc9f)$NH&AereDzftN01|Lfu5@>(yXA0vz%KqC*pI(1H>Y+5gV~&#qNJ!{C|mBL z0-)jwTXKk<>?tjA?VRe!T@z9lxha<~5!-NhwUn4VoNLyW+7+4e*$vZ)&3J7}CEL%+ zT{35%-ytod#qZ$yB$vhOP#mxm!w?vE<{UesxS?zr+B`e@@z#|dr}ab_+kDS0r(?Jn zPUrPOPia0nveeMh=3nl8-}6XKqB$Gp1O%rPRbE^oj`4?HLSm&xtZm5njSU4&`zF#I z1jcD#VvU73sKH@io(^EEb3FvatRDyMWaiKL-NM=@!}{vC(q*i%H=dSd=CCXKD=2OB z6;#enhcj@irX5ht=_t=kogkGlxM`vg4A=QN5e(miPW*lrJirR8Q~BzgWrXr;17|@} zGt4f{^Kq1X8?$UuJH;;51t*kU!e{NF{NiVF#TT%A@@JJP{4293R9l4)5O3=YYF^z1 zGwNQs^Du9x*S9OdL~Cse&EYX zfx=6mFgW?~lBw^)%*U2`F8GCV90xgp=BDIu4q9J0J2Ajd1aT63-~Hr`0qjtqS4ubQ zDNw_&3sa5azlq`>kI62+;)nJN>Gj+Um0CoIZC~FElwv`&)%Y=+_M3ULB`iGn8lXu#=XMX;4pdMZVVzr_|WnBBgWA2vEJ#~ zds}Ah3~NIwm1L_hkfc8|fG=@hi{5{)o$Y#O@1U%vNd^546{5`p?fA|4lcx;@%7l2=t{hPDR-Uy@*?-#m2R3(JKJDjRwO9B>6Y2>4WW8N z^BSnsX}l zHx>7rYI?SYf}(;UJMoqad{J}%|Elae;Hm!J_^o8`y-8(eCKRG=6e;uC+ec`Z%1v5C zlsKfUN<}gnMhO*Kq+L>JD-GId{hxC_*RAXO`u$)3|9!n~eLU}Ho##B~oadbT`P}Q~ zcHum_`o`6L@=Jy8?dOKYxK zX_hzLe4|Rt-bjZ->({mIme5BYO3*X6FQ^IBP#s?@n;;=I~f)oso%u73)hpXe5BaXu^U?#i_5On3L> zgj;3JK|`k$cFixJmzR3nRCjQe_ezng5mHQVyFqG8Dw<;X%HZDll`pk_Z#%N4#qyiP zVE<4`)0E_ITB$~zdcQAQr7(9aH!>+T-P%-A_)XtztI>gP*SuSs_GEoy>Mea$9yH`^ zX=iw5qiM#|vVC4m37d#U2eX9a9q7pd=FXk7#M*NOYU1mxCy5yuTZKNBxR8F%$$7fB zWei+!msT67Y_N(CJW?7nG_lm-mrWAWq^UB$BhdQ({ghhij3@8kGFrku95OI6cror` zQ%wnz>+h#Zc+3BAhkVQ}xb^!x9I%`H=fsE^6uT@cWU0~r*z%ju$3)p#59ZwnlxZtG z>s9L=+AF_7T_a1}ZM>dFYM;Vh^X;+4VKW=6msPszRzwLWM3qc>nAfKsSdvn!*QOA% zHD$2P?$WAGZC!co$m_OOe@wP{zuN9c|JOS%TuOH}V;Z_|>Ha|CTDtNvpO;S-_drzlg#-0oQ1;^B0sCo6@e!7QR?Nq<8X+qDQ z_|~$4lAb*QE8k7l%IsR^nU%TwxL^Cy5?#TL)YvbWH zpKQncY>SS%3i*ha`VA|# z2p>3nEH<*N)BA*Dp5CroG2*|ZRX=6SzBku)RjlSFUd!2uTYIf`A0GAdCr{Kz-*8?R z_3u%?)25ev5KGAyb(T7LUPpRdh_mD+lTtx7!_iMfy$2ocC);_N_WgZN9czI7s zefsKoSG>ayw5S(pxNMuUQEpj@_^)TYmKkmzOd4v;p6QhtUvTM3cJXhYw(*%{L9gz2 zv(wE^A3Rs3PkI(NsHXg^a6r}WLjGaX%$S(&abj5(*Y3}FFJm2dahFMLa^ERoslM0+ zlQ--Ow4Rx8TGDDJ#bs(9KG~|~upN_gu-J=z{p4=g%J9uh)Y6*^ z6cVpLh+T1Gm(%4XQJdtZ-?p@m3HZWJ7SAN*4 zZ2ffA_ukR%iYigUrcb}!D||M3&}xp(aRY}Fd*?j-Sn&13p06uvn7@DBf6w)<)l;Z@ zv1PKw6kWA>7cEOP6c-nG42TqD7e{6=keu_ zCan|9E1^ymEI<26+gxn7bc3{4Tju0gYpI<{?=qacyq7elT9m5a5Dn08kj~0kB)0fq zzSNlgV-56E{5q-`F2={#B^Y0Nut4KY*TtQYO-f!TJ!*cgUz2BF{-n?T*1m*4r{5M( zs>~siaRK?sosVADw;!o_RZ)2E-Ma&Cr$@by6*Ro#b>e|z>k>Vml(-wxT?q#5LJ4Cd z>y`H&y`5(*HgIJ|t#j8lr<@S61>-ln#LZThbBolg-yEynW#e=tB-~WtghG;wu$9!{ z#fE+N+vjynjo|AtkD;zlns~qPbcD0=N5A%b^W)5tcM7F`DihNemkBPbku=m^)>EVA z1{*;E*>iilewOX~9(&8o*>J$wOe|FmhHs(0verE9t~wvfuM>2Fj>(QcvfxUf4(!nD zeKKDv6{kj9^P9!bC{OXZv(VGj()QxrIqS5?_n5Z6PCit6>d&l2*K#}dA4^#E6RF-glo|1tFH$8I|*TtjXEvV*ZS_yVc>@Dw`>fffX*Dz4F zanYZ{WgD~ZY&?}^>hHPOv2Go2oMU8@_u|8=1nzHo;j8Dk%GdS%ADr3*31``5fk9QzZr@)K>*#Nyq&*jVw;)37j z6dOifnXvo5%^su8i(VJ>B}|LBZ@a7f)ubinc6JX`?;N|UQU86Zi)FZUYH?1#u>76^ z6$8di(@c|@%jZqvag%;~Vw%$C`69BZmETti`WqhgJh{s7nrTGY#NcXX#aM&J*jU#O zxv`!djVc>2zYIQQ>Mh`BghqW*YO%ah9F;$Jtito!_VjlHeXr{r;?CUe4D59~dg^K0 zSG(IE_8r<=7&XT{WykcgInD7Le?4;blMEzF{^cD%Yx zi-ned@6^@)fHJ3;ClBfFPZa#jtR1M|)6ncV~)f&iT38dP>H5^Jl-EW~*NkZd)B{J*ji5Vz1V6Nzpe$bM5C& zv$0fnQC=|QpS=82O~J|c0@t36=|2{Eve&j}-XlGe<;D4Ow*wUu2Dsdu`dX7sjxrtU z_-{HzPT5u1R-$NNJE`A9_T6&_@n~)NHHV}>=FICpbh&HgnAPr*Lt~{9rW^a-*k|U| zUD)R$vopnE-N`eb*X)thx;L~fvh19C9LDT>@Swi**Q6LVQ0xa0i(jUREOju54oGn&X^ZG9xnTy2S#|*JESz;_Fi$$;6U5W z!wIk2FH7%zd3L_k7S-^QmYr^1=H5A%h18C2n$@&-*27EFR+@O-&+B?1vM8nHfm7#G zkyo1hp9Oe*f@W`@|75kyVyVfi7fne!c6XEdp+PglpQ*FXO)Utn+CD#S^m8Sh#`KyQ z{44b5x`r_2lOK)>=$Vok)zLO)|8+)2QO1JJzc*KH*|p);=@n{Y$6gB7o13X)gC?cO{>j;YkqWVH-fMB&_TNtd;bseWv6ou~FF-wa8lHjD{a?!z`Si~v zE;K4UDs0J8&bub~@m&)N{H>|XLkn(h_Db{6sTJ5L5gjdJE`5FGntW|uF)_1OSF{(d zsa=V0lPEOzcw1BMXZvGcL&Mde*F4XYrtFDh{&@3iZ{yW_Sug+C{uUf3tg+!YPsypf_=x`pWa`7Mq#aYL~h{S-pP|JCn=6ow5VU56_ncYY@zu`T<7Xo)7a^ST*Jt%?b25oO^j!j^|h% zp97io42JHrql3M(59dyZtdB{WmF@Xq*Y1N0a{Tx2TDJLgP{s7QWo49==j@kbr=yzk z)|hdIVp-*-O$XLY8avxc(5Cc(DT6u447hN+Rzxtm;Ooxg%hrrJ{QYQD+`yB0**CtQ zI5O_>73Sx4UzB5CdE6M#KL2#zj}F1GJ=WRr8gbn-i|ZFo?Ahsm;=&l=>g?r$HwHcX zl^+~Dy?bSJ!@}EsS>^oKAMc9F|E*H_apChGwJq6)=l zL*DxsGr`eM_pNzg=ydBy(Z){8d3imO*(dUS53f5hY1VwV4rWxt#E^T>(m%f!vuqzF z!+7xszRpSfo7>q7wi{(-2C_DM9XPfjV4!@1NRCYC_nNeoeZQ4D%EE51n(o%Z_ptO% zbX~a9SJ6$jt4nrl?*BHkW72D((z-FuDEwsP8lUNR(w8?zeHRMn``i~Coj9$<;9%;? z`$r$dtKL6-?xVXy*UIJ0`(~o~OC~HHO}xri*-|!IF9J-_@2FRfb!g z9Q;64E|~O+zb|Fniq1K0*KOifR3<&Fa9qv1#$|k=+`Yy9r4_!x2}^|K`-MnTC+Y4rby(<-felwvsLti_n3#9 z1Rl1^&b}Z$dCmpqHH-c2eXBNi{y4AAI55%R%c`~9`u0C9UoDPXAUgK<^gCu7-)%En z(N=lAEN0fCLYE)r>BpCBvbKITcm3n@%zMS-1;#t1v}eZI@HlDz=IXEeA+Y28-7(YE zPj{(mxCCZ?64#s=BQa|+&$K6dxKlL^BTH7s4oXjUle$MOn4$Q7^oj9;Gd3-A{q($M z%gS93WG|SkU4Lms&9iM<8m)gE4wbA}S$0YK)0F9zMWY>}ox5!9Z%sH6(3QMFO{koA zgPI)k(?o9@t-hk7S$WpleJ1u9?Pp&Lwrm;2v>8`Eew4c8&jo3R500`M^G&&WtF_)L zhk;|&hlWafLpBs{TV6h=<*IO^X6d0g!9F0cA z#D=(*S6OV2%2ue~EO=p(!_-bQz8w})eCF06d=D1waT)L0U3bW4WA!M^sT4TIZzH7g%CG>iY?{ae2; zgS*i7Pw~whP3|*;IruV=O zu9j}|J;_6^47U6F(X_N&-#N;}Ke4mE0es{tzRh<)f?S2%@r|bMlI!a6oi0FV^3Q!^ zxyjYm7ry!QRjU9aoR*y+%2-8T9hPMHi4i_Q4MwLRx$4$sfL(ld-nc$rZJN*Jjqe5} zLc7k-7@+l8n=@9@e8+7WqcsS6#-C9^dk`DJkfQxdUdhm)X{Aht8!bDuo}odH8CMc1s=srdkH@-UgnsHv7klMd93Td{epA1(iLOU(y zSI0}PR!aF*8;~n~JHH~DuhZU7R)f%91o?q~*sJ9se!s;9u~$o$h38I1CU$=IDDEaT z8oh&mYA-MKbEJh8R`?mvMrLjGTSp7Gr}**H&UEGa74k@8HAjOAKYx|r;#xG3i)#jI z`Q&GXnr~Br$o3A!Uwa|nk6V)1y>i5FGObvs(r>Qt4S$Y2s;jThHNHs8`M39x30aL{VioB~UB=+0Ts@4*BYLiWb%s@vq`0Aupb`M-_or z&+Jf@x&IVY=EB879j*2kr)8VZ`LlW??6YYrmoyg_(~8|AXP!~wwRLU&LUh|&@A(Id@-BgN(0l2B zhnrmSz4G5INv_g|{15SvE6ZR0ho#8XGx2}}G+&xzfVKpo9n%b`rTG?V2dL0|X%+$1 zG~ZOq022v8u;IQmaj(Z*qEdfEayrO8!AcL0naOmlq@P)%R)^#-)^6WWy* z0dp1c)d|(Wqcqsb6Szi+fX=Fct7*0iV*(HIhyk0soc4n3G`O{`RS^$=CuH}9lCHf! zE-*((6vGRj-K{W$q>4nw4}u(On@s}UXt^6la*wZuLmDAT)a(^(UmIv1m{05eZ5{Y} z6t;J;e`?@#V))(0z?-x)ty=;`^$G1(P2eJ0)fqRzu~v$3ACw=CtRtFgA1H`64?$$B zPXtaQt*QOm8Q4W@xO6SBMwVz`z6^xBn88r(-B*FP<;hhwcM!|cR=yw&8A2;p2y$>F zR|CO8kgiywAS@`+h+L^>2PyE9E9=~#G1}xR@N`fq%_rCtq@+e@;~oSpq-lwdf(Dcc zZSjvFSl_U|@xO!Q<;a!2Ot2hH^N|a-q&>*i3x-t)^UXC3R-wILq&;81BN&DZwywV`_zCT~L{)GzH&LZ3x_`$Dn2fsY5OX%D5{?nA zHK+;xEkPs<&jlZ&J(?Vr-EkH2f0H$;j%9fS%+j?EZNc}X2(#L~U=cc$hCRV0v{>Tz zYZ{`Xxwx#PkjaA}d&CrpQL43k6f8fQSRZ}tdPAie7uTG%s7NoEz@w3%DELtGBDkLR zKXz0IOn}&bWq}YII+cC3Lf&x`nzMGuO<9twyF-3@&xD{nK~=H-V@b$Ryf}Ec!8*j1 zR&Z-dNS7oLJ2W>$iKex>hQOf3>XY3=F48$X&nHBdZc{`|NDGbX$A$3I-DI8|qDQwg zXmf~%x**89>uk|2bS3i$TAv&uU8`6c5=_e_9ttt08&cgCa+tm;-|r%J9~Vn=FNb7H zldBgGL+~eG`Or3ba`kXRXgp1GGYK_QCbTWip)f6CKKps0OgVCOE-dsL?aY~o&_}X_ zRlKvA06c<0jU#0E%N`p=68=Db&!9*_ zgu1X2LqAH3h!B;F{3uOHydQ@xIQu1w3jHV*#igu!aF-gnI&t&J@Zwu|x$u(`#2fDQ zsKO5vWACtH-pURSwD>F~E&eYzMzIszkC1^srOr0YBie~5f69huN+(JRq~uVuKc&YL zOa4$n0s-(xDfvS~;$L;RDnVTX(F%Ou?BPCikkmj$0hAf{c(gu{(m_8#kUJV*PtgBY z4(A2Cd2j&*4eKSr_09em7MQNF5SaXS3MqyG)C@N$!*FH4s*?D-&@(WnK>^o`B@(0F z19lL&%-B3!TvbW=UC1OD9B~e!6bY-toy^&9fF%f6@q;15ud1Z`*D$LxDhi_Hc|j{` z2%?mE1aBbw5K0A!-SCh?zt)C{sAGefdf!b3K{OV${Pi6hbVkO(;5%lDQ5pYyJ}^kb zC>}Fx2mY^0%Djb5DI$$#PkwalXM_~tkFZd5`v7<($V}kiA9IK1cU?~jAj3Nz;>b9H zqCNSU^ZKO)2)u*0A%{>9ni@h);f;ZoFhigvPwxGrq%nk2&;ZDNWyPO6FG0>54Gm6?Lro`cD#n-uRP`;a64C zc2pcnO%=pUSp}b)UZH_FN|yU)P8elP{Iv-Ke<$=}rOIe|7^Og{nV6dL7;%SD&Ah6#V5+r6h^X~JBo3kcmLo6k(3G%6^{bQ@jY$J`MrlINk;+&Vd&Wa z4QYIU*6xg?6bW<&Luwz`kkVgYRHFe({76IVKYA#m_z;#G>oC;yiFPABhmu4`R#D0% z3rw2Q5~ZL=3*oIl+@NqEJor%+lcjG81^U)}#Y0I6C4TjgrV|(^ zz{l|UUu8j82#gZAg`EAWN;-F*Fi{GuoTK0;7h1d+W`W9BN+u_kk|Lf} zxSI0{0_$FQTX1+b8JWaVGl*xaW5KgrUbeUqp+3e`i%~T7=pPRuRK}#Fh!dkcb}oMb z+LA!49*5Rie$20g7R6C&M9cO#(DHmVn<|2=ma~T1YYb@#B9kl-NQj5+;e>dWf!UM4 zbN>XzOfbMXH_R7e^N%40isC^_zA)|PUSUrK6u5+yCciLrM}&r&3Mmm}x0n@|TSa0H z4D3Cm$s~>zG@>^lrFMf)GjgLpa&vY832xUZ4=tv4Qc&;5r#(2M4`N}zPqaje$%Jzj?=s5E$U&Wd-@ z`UJ|3*q{9M;Es>r=OSR@9JD&Vv_3L*K3T_#n)(`OdL)B}q8ShxT!s);4{yD(-~u&k z;mtXr=KA5LDwDr)S@k={dqSk(IH6q6!VT(3}HVJDx*-b|me8 zD##I6{B8|53lM6s3Z|Ab+1 z1>aAp1z-uS_|;a62s2?|W69Ep*NWRN#mOWU{I2xr6n$K~B z?7O13vJ!*26%2k(OP<956hBjK8LdgqY2Q1^qze4YG zDLI~tnY7fE6jr<5Vu7za*t!JK?|P^*1a}Tkp}6sGslYTRi`~g^Q~>!-3?9YM`dwIF z3r#%*UH^M8lp?sABW?e6$><24)_7oY;+%25XVXG%+h7xctt{FGs^Sps3al}rsA?M} zMMC`H+JZx`P;V0K--^-WZ7|refNB~DT+d^7mkC`9TWh6?x4 zW?<#Qn9-lCggv3-A_#bN&(7M;m~E@gs?S5P7mi0->A?Q0KOvhM}+$MS=T0 zh3SnPK4kI3__hNyKAe?;^f179BgW5{(m2edWOflDr7-zMmZwf3lCMczdA=TG53Et> z&q3B4Lk@c4GeL{)VY>S>@IKA%FpMZtx?(H$FuuMFTOm2Xhce2B(+A_$I{-ghPJ0o* z1GX$cb>H;Z__!j(q6Xfa#e-r6%?hJ}W>w3%KIJ`xZXd96uAu9W(q2K~rA@RxJ>etN z53E~&m9u_rs-(3-6)lJ^RYDkxc0v+k2P=1igCDCqP{_KR!0CwE6?fl&tLoHUC|B)tXthn_>CKivcm~Gi~y7yq7%zW;u5Yt}Se{BnSD? z+($6uuqDHP%({#h-!&k~S-WSSr7el((oIK(xzP63bL{L9MW+!|^tki3V~DSn78u@` z$P?%_hHTrgloEmy0%2s32lF+Svd;r3rX5Sc5l1`pOPXi6h#)>?9h0JV|1-)cgy5hH z>=utkMHiqx>0JoT##~$bORDfn{NK#&xkwv?;#Hcg{NzB@bvGE4yo{%~F(`94OrrRZ z_6VlVxq=18A&Ej*Q39_FZwN6ikq>x(2aOMPz%UQYhor+$9ENnSvfC|$D)S*E7`lWZ z7dYi)Z7-yd^-fBWG|r?eyNK2Ed#&mn|nTJ@m{D1uzdYqkT1TCJ^s7+&>kxm0QBe% z-I(FC8GbZy2l54Xi~u&$F>aYOQY(OUQR*Je2?rYDsIGwJdIwfAqni#E1e4r{SZJ8+vFQ&KJfD!lAzVd7Yh%K4iZPl3?fojj0z=V>B=(T<^N( z6EwCJ@|LrRoA8Jo9Ob{sPLBJJ7J->Hy|k)zy{saX%v=k19+PVpfTLFFkps6JX%<89 zaKc6vgM8C#EH8~tz4jb~P8YMLpUW7!^_GTy6vO8a_@r9B1gK**(Bl$H9*x!Tl0X$A z(e&|HTKwhoDe%o6UtrVBdEULtl;$r5VRA?`QL5Y~3)%dH7Y8BxQkFClD?b zp3Iqdfy)Ava_(uKPC`lhVTd{Iqm&41<>@Y+-@v*bSjP@)ga50NxU6Z`!hNi>-G+V8 z0{bc0j4bMX=Ea8w_Q8f6AC!oLPM&Rc|3K+>&_adQP!V;&-9L(-?!5_CCW95u79K_G z_fuvXn5ks3g+Cg_#pNS1(v|Zw=rFwA&$1_Y0PGbw(bNJbFLC6Y2YU|eiZ6!dxY1C? z0Vve)eyIvmD?MljD?C`yClGfjK!-xm;-m19%E1sXdE`_IJ&C1!FeDvLOQpddgj$BF zcNftX9+tAsBz|G4KJ10C8smeopyJvwJZ{N3Jf9wg{^BfKMAu*iDk$?HtCp-j2nw#R zrHys1^^!#y9jt8;7t=-C7__{Fw+jU71zR>vo^-R4II$zIAiham#ENEAN|@S9DXur%^L%&N2FFeKhk5Pd#R!KkT@j^xr9IOx?S=LV4OY>Ki!AXQq8H^q5MPeDK+E&Dd#*(I1 zw0tm{30h)>M#eV#FwIJmRIHrRB>ZL?wM7VWs~0}~IkTcg7pyR1yj^p z1g$y(VE`-cU%JDD9HFlma8EDi*c0fcRq=O&Dz<66+unuzVA>c=dsqQ73r7mw_cL;*v8Ai+fOBRUm-Eqfj-X3<|m3j3ZKQ|S^e-)P-6LuR&xI+ zrBA4Wl`y2%i+Ur;WbhDzBTvS$CRRHjw@}<3zFz)``p86X7xzZh;@-L>#+rBqco+2H zQnv&bSI4-KF3eQ}-Xkzyxu|(dlNgZMU$hDgFES#SJc>2)R!25!&|W-I#{g@k{_H5V=M(@m8mSOD%D#K`JRIh6>)sd z*Jj5Fsc><_5zLoz~z=wX7Lm*O*u{_Pg3}cUbBk|+jTF3~< zKl|`cw$=M2RCu`Vrr87$msy#>XL0LCE@1$X}%Pkgp?k!N%e=k&obai0W^P>{5 zPD+W69Q4cY{uPiwh9_B{dWhfpmW|I`EFnF|a5UxWLsWGVD$&&^p=yE#xu4CyC4raC z=g?}%I`*q7=?|(r$!cZqN$5nGr&v@G$<;#F;#la{LM&dPS+$fdQMJ}}P8$A9l^?7^ zC$V2uNi`^=mX%qJAjEs{w>R4H8v=Hu2|lpID;RejkTv;ykZYo^I!WXKxI*Ya^! z8BAZ}!8Oh`bUIpGN118j=|AXYQj!3;F9A~u3eAZN<3g4%3X5GfEix!JB5Zb0Y$$S*kCr9BWtTK}ciUCO zT@QP=Ruo+icNI*kr(}rcvX07F->F<&7wSjG{EjNtY(m;uSPzk0>W@y>Q>L1@03g4P z2La->*F9 z&{(m9XjDN4ry*}}U)!IC7~IQ6{-+`L@lvPW2m~uQ9chFQviuq$ptxK0_ayRtgmQE| z90GB!6o*SNs~O>%B*mRpD9FVX07I6O>(NQfC4+Wf@sUQtXILu%`9@iY;Ymmq&Y{uL zO!GVT_(+mEmCPnVP2k&_b2QZW#zz8ukB_EzKa0))uolVq4 zO}zFv@`OAHhXDS80CKJsd!P9r9bsP`^zd~QttaRk}hz^ImDrpX{@BignMbY9rVR9Z=!^p4K`>P>Z;D2cNA5TsXlaa>HD0z3R zd*pYo{ndRy=>JbQ`64z{d@NLM239=s3Gcs(S1J8JDMp#ilnPNb^7+@lstQ#9-&AQH zqm&%*vNZA;rN62ywf~2zf1X%E#yt__b}%%z1yX00E}~i}Gt%$Hn9yyE&a}V{D0prA zfeD#rm@p36o`vZikCg7E(NB3GpZ7zZ#CgoV#umk&r5p&?A#}j!w&y5aGR9rw)+ODA>U9Csl3K%Ug#W9Oo<{qk-X32$bT7|G z6s>*%>lUp2?&1Q$&o4vPFNdjHl|$gi3SV^pfR7rIXoO`E4;yaWGVU!%t%Wiq>tr2)Plv_Hi%jK1b=3;kBgXO`{PsehD-lZf|A3;69BKU!=OlR|!o$ z&l>!@6rLs&!(^Ka69(t)Q8EY7yjE%&DHij`U--lW^){zke|3yHR~bgHxixsHp0tlKFa;+CPB-&_3g zp#jXJoHc_k4+C|zL(zZqg|86WHU?IA>{jsw2va-U7jh9kjk9le~=$} zQqZG~Syj-~OOzC8!^W8%E{`A;QXp;gILu5jB5jyNd=vs7c|*(yMHbmyfDwlSI!&mt z;W$L#3`9VaL%Poe#a*C`h>hl%(=%+qokp3Fak@W`fgH^l8h^Ve@62=51;KQKg`Kl_ zTIhqCE>U{Koi~@joqz-e>hx!*knIRD^r}&d?;Z>^D-A9#7@X`^Rg!oz10_Z<)KSXt z5|eZpBBz~&3NFJ@5^jr)_L3#s&=y>}aSn=E`RMUw7!;T*rolPt0&v`fm~q}ikiQ3W zsUw{vXb-NY3BOh5Q#)tiT?DlX=K1pD-JSQ#{zpDg8L{Sz#kz_X6YZ0Jp1sI%vD=+Syf1l;L*9P>`m zZ@PaD=9)x*E-qIN-tJe#rW1O26*2|$X1eA{;*SJIgKifNUSU2oc$cz5;zNwl$h8Yx z!#>8s1yAuPHY9*tUxS~<=5XeV^_eDWp0x#Cr(ig9)_{?+Y$0*vat%f=*2lO8`h*nN z&}dYD4JI!Pbz;a*kA|A0{6-<&>u}_Tt=y>>+3O5vH~jmc+T`$BVFH_98dY6qS!n`6 zo-00Vh#x86pvZ$J$m9k<_@M*bR$?XX2FrnB3~gD5G;dM1=qLO^+)}y;R5>P16%dV4 zA|8=Pm7v{~(C+CR9?56WtZ#2Z;fS3-_dfOBRk#J{Dtr{+z`J9>ma2s_ zq?s@oak`>oGg4^st?)K7!^~ z(+v~a23|!#&bo1QUO*wu|7VlG2wEW)Lx*I?W3caC%!c5OUYN9qYvNA;GO1-lqG&BV zF+!5~iua9cR^U|=4A$8kRvy)}`9)CQ6V{yZ3#&@Jj3IkuSmiJNH!Q240yM7!Lk{Rq zwZACpXCT1)gx1ymjAfw*Q^P-F>Lg_R97ZsH zFfHkm^D_#faRmk(XEZMJpuyKLffYTcGzsgRjwe zLn7q!snBg2=)MFwz&Ybiko!ldcL*M0EPnyhE;xl6UVy9jU~*?GRelMrz>x7vfHvu4 z$Oaip1gMcX5mRoNJ2I-FS~w0v!HXm0hK6i@aiq})101We=>t^@Z2p17v;qXs(LR&4@e>LWU zY*`i{ibMxsaN`E|_Jgf22{dH)2JY;@)TlQ=-I30wilKQ+0!IH0!yAmx%VaB*M*eSE z5nA*XAf5d*z~r9;|rJT+@Y3$*qSv=&we z_NyxCTOC`03}Q#W=sjpLxr`x_1N=DyQ0n8h=tEO^G&?vDQS_*q6>vN$xu&lE-~s`Y zf`Z6{Z3-7wryq@wo4aH<9pD))WHku7*F71*h^;JogI?yY>c%pxa*|78tVo z0MOt!Hl%`1e1H=W3|+y{fgfy03$5XS4<`U}xBq;j^&u>nA3R6So{M-8_g82-SP?~M zKEmhSSXK8&P<2N6ALw8oB~4WMzkGg28a7B5oJJOFacXRS5!CnzCIxJ|$S&rnfe)|B4U7N!u+%`m<>`!323v(CcLgo+|Dkr=wc_d$?H8urC3 zNS*i|^aZH0E|@wGb$o$QfOY?UN_33zo zBM7Ukfcem-X>g+r+%+7?!J5Xvtg(cvEu-{j05mBPBEZ?Cj3Ugn5aGZQzlFYo-{Jdc zGi$!HQXvylS9D_PJoFR(AiPRLKz-3gQ{e$sC1R{cSJ*KSj0J)*&NVXkHO(sigB6bb ze0aFp(wfojUo$6?!(OR1meQkPz_#W&l6*V*8hM9kRQAZgkl%A z5yTZ~3r`sa>@a7+ej|V*I;%(hBP7lfGzv|A9mp!)aYxn65-Y`xSOtw3u~|{&loUZu z>G1Fm2%$N@ARf9J|KKNn!GjMN>co(=I_j`m49@r;r zY}I7GV7S?0;~+QLF$cjsi%`pN8OxWC?W9A^4xj7h_yA@E^QqdaxLp zIt}iv#! z#6}rHEKmMEemyc}Ha@0}iVDZjQ^%lI!}el`a0;A=a#ndwpNP}=A#8pWfA8OJD-s6( zJHN7V88YD$|NlP1J#vCuI>hE5M_B(p&dtR&j~y+%G=Jnq)nbs?V46JOO%H?{{;zxS zBirX;AaL$|#5Gy`u+1g`-XjVQo*u*2!jFE6vQknK3VoiRHW->ss(#|jAGOV9VKCV` zKvB%OU43hZS%V1|`=Rmw48`*cG1nY=LxA(m-O(y03W^*(C~`QrDJ#5a+hi|*hn|Q8 zcr+&(am&QmqAvFkX_NpIVlcXUMur76c@PXnbA%{7hRr_?DN3@ITVqL3r5(qH3{ak8 z6xp2Z`WA3_FZdG$>!BZqrh(;bcG#%;gwUr+B#drSpiW@xKX|hgYWBIxIPc4hA6eJ(lwkg7 zq99fV6!^Aaf*b0QVY%V+PU21r9I?KDb%?Xy)X&ql0%Td4e(DKVK8|G<9OZd&L}30C zv_m!~oE+c}$%2{R&oIG>JVB3QX5XbICOXT=_n%od{WQg2WJRrYyosuPt4=wJ-n~#W?+D@In#yh@o{Vl*plhlzj$)?LrqW-QjOLQM7z+6R E0aN@I_W%F@ delta 50357 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 z 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 SQ>Ip#j3E}fxXp3+>;C{zAFgKr diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java index ceded3ae1..b71cfaa7c 100644 --- a/app/src/main/java/com/itsaky/androidide/EditorActivity.java +++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java @@ -33,7 +33,7 @@ import com.google.android.material.tabs.TabLayout; import com.google.android.material.transition.MaterialContainerTransform; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.itsaky.androidide.adapters.DiagnosticsAdapter; import com.itsaky.androidide.adapters.EditorPagerAdapter; import com.itsaky.androidide.app.StudioActivity; import com.itsaky.androidide.databinding.ActivityEditorBinding; @@ -47,8 +47,6 @@ import com.itsaky.androidide.fragments.sheets.TextSheetFragment; import com.itsaky.androidide.handlers.BuildServiceHandler; import com.itsaky.androidide.handlers.FileOptionsHandler; import com.itsaky.androidide.handlers.IDEHandler; -import com.itsaky.androidide.handlers.jls.JLSHandler; -import com.itsaky.androidide.handlers.jls.LanguageClientHandler; import com.itsaky.androidide.interfaces.DiagnosticClickListener; import com.itsaky.androidide.interfaces.EditorActivityProvider; import com.itsaky.androidide.language.buildout.BuildOutputLanguage; @@ -56,7 +54,6 @@ import com.itsaky.androidide.language.logs.LogLanguageImpl; import com.itsaky.androidide.lsp.LSP; import com.itsaky.androidide.lsp.LSPProvider; import com.itsaky.androidide.managers.PreferenceManager; -import com.itsaky.androidide.managers.VersionedFileManager; import com.itsaky.androidide.models.AndroidProject; import com.itsaky.androidide.models.DiagnosticGroup; import com.itsaky.androidide.models.LogLine; @@ -69,6 +66,7 @@ import com.itsaky.androidide.services.IDEService; import com.itsaky.androidide.shell.ShellServer; import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE; import com.itsaky.androidide.tasks.TaskExecutor; +import com.itsaky.androidide.utils.LSPUtils; import com.itsaky.androidide.utils.Logger; import com.itsaky.androidide.utils.RecursiveFileSearcher; import com.itsaky.androidide.utils.Symbols; @@ -76,13 +74,6 @@ import com.itsaky.androidide.utils.TransformUtils; import com.itsaky.androidide.utils.TypefaceUtils; import com.itsaky.androidide.views.MaterialBanner; import com.itsaky.androidide.views.SymbolInputView; -import com.itsaky.lsp.Diagnostic; -import com.itsaky.lsp.DidCloseTextDocumentParams; -import com.itsaky.lsp.DidOpenTextDocumentParams; -import com.itsaky.lsp.Message; -import com.itsaky.lsp.Range; -import com.itsaky.lsp.TextDocumentIdentifier; -import com.itsaky.lsp.TextDocumentItem; import com.itsaky.toaster.Toaster; import com.unnamed.b.atv.model.TreeNode; import io.github.rosemoe.editor.widget.CodeEditor; @@ -91,15 +82,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Stack; import java.util.regex.Pattern; import me.piruin.quickaction.ActionItem; import me.piruin.quickaction.QuickAction; +import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DidChangeConfigurationParams; import org.eclipse.lsp4j.InitializeResult; -import org.eclipse.lsp4j.services.LanguageServer; import org.eclipse.lsp4j.Position; -import com.itsaky.androidide.utils.LSPUtils; +import org.eclipse.lsp4j.services.LanguageServer; public class EditorActivity extends StudioActivity implements FileTreeFragment.FileActionListener, TabLayout.OnTabSelectedListener, @@ -125,8 +115,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F private static AndroidProject mProject; private IDEProject mIDEProject; - private JLSHandler mJLSHandler; - private LanguageClientHandler mLanguageClientHandler; private BuildServiceHandler mBuildServiceHandler; private FileOptionsHandler mFileOptionsHandler; @@ -139,8 +127,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F private ProjectInfoSheet mProjectInfoSheet; private AlertDialog mFindInProjectDialog; - public final Stack pendingMessages = new Stack<>(); - private static final String TAG_FILE_OPTIONS_FRAGMENT = "file_options_fragment"; public static final String TAG = "EditorActivity"; @@ -206,9 +192,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F createQuickActions(); - mLanguageClientHandler = new LanguageClientHandler(this); mBuildServiceHandler = new BuildServiceHandler(this); - mJLSHandler = new JLSHandler(mLanguageClientHandler, this); mFileOptionsHandler = new FileOptionsHandler(this); getApp().checkAndUpdateGradle(); @@ -417,11 +401,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F return mIDEProject; } - @Override - public JLSHandler provideJLSHandler() { - return mJLSHandler; - } - @Override public void editorStateChanged() { for(int i=0;i(), this)); return diagnosticList; } @@ -890,7 +857,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F public EditorFragment openFile(File file, org.eclipse.lsp4j.Range selection) { if(selection == null) selection = Range_ofZero; - int i = mPagerAdapter.openFile(file, selection, this, mJLSHandler); + int i = mPagerAdapter.openFile(file, selection, this); if(i >= 0 && !mBinding.tabs.getTabAt(i).isSelected()) mBinding.tabs.getTabAt(i).select(); mBinding.editorDrawerLayout.closeDrawer(GravityCompat.END); @@ -904,16 +871,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F @Override public void onOpenSuccessful(File file, String text) { - if(file.getName().endsWith(".java")) { - TextDocumentItem doc = new TextDocumentItem(); - doc.languageId = "java"; - doc.uri = file.toURI(); - doc.text = text; - doc.version = VersionedFileManager.fileOpened(file); - DidOpenTextDocumentParams p = new DidOpenTextDocumentParams(); - p.textDocument = doc; - mJLSHandler.didOpen(p); - } + // textDocument/didOpen is now handled by CodeEditor } @Override @@ -1020,12 +978,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F } } - TextDocumentIdentifier id = new TextDocumentIdentifier(); - id.uri = removed.toURI(); - DidCloseTextDocumentParams p = new DidCloseTextDocumentParams(); - p.textDocument = id; - mJLSHandler.didClose(p); - if(mPagerAdapter.getCount() <= 0) { mCurrentFragment = null; mCurrentFile = null; @@ -1042,13 +994,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F LSP.setActivityProvider(this); LSP.Java.start(() -> { Optional result = LSP.Java.init(mProject.getProjectPath()); - - if(result.isPresent()) { - // TODO Handle initialize result - // TODO Register server capablities - } else if(true) { - // TODO Show user that we cant initialize Java language server - } + LSP.Java.initialized(); }); } @@ -1169,8 +1115,8 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F getApp().getPrefManager().setOpenedProject(PreferenceManager.NO_OPENED_PROJECT); - mJLSHandler.stop(); - + LSP.shutdownAll(); + getApp().stopAllDaemons(); if(manualFinish) diff --git a/app/src/main/java/com/itsaky/androidide/adapters/CompletionListAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/CompletionListAdapter.java index f587f2185..c7ad0a477 100644 --- a/app/src/main/java/com/itsaky/androidide/adapters/CompletionListAdapter.java +++ b/app/src/main/java/com/itsaky/androidide/adapters/CompletionListAdapter.java @@ -16,9 +16,6 @@ import com.google.gson.JsonObject; import com.itsaky.androidide.R; import com.itsaky.androidide.app.StudioApp; import com.itsaky.androidide.databinding.LayoutCompletionItemBinding; -import com.itsaky.androidide.models.CompletionItemWrapper; -import com.itsaky.androidide.models.CompletionListItem; -import com.itsaky.androidide.models.SuggestItem; import com.itsaky.androidide.utils.Logger; import com.itsaky.androidide.utils.TypefaceUtils; import com.itsaky.apiinfo.ApiInfo; @@ -27,7 +24,6 @@ import com.itsaky.apiinfo.models.FieldInfo; import com.itsaky.apiinfo.models.Info; import com.itsaky.apiinfo.models.MethodInfo; import io.github.rosemoe.editor.widget.EditorCompletionAdapter; -import java.util.Locale; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; diff --git a/app/src/main/java/com/itsaky/androidide/adapters/DiagnosticItemAdpater.java b/app/src/main/java/com/itsaky/androidide/adapters/DiagnosticItemAdpater.java index 97942314c..3102e06bc 100644 --- a/app/src/main/java/com/itsaky/androidide/adapters/DiagnosticItemAdpater.java +++ b/app/src/main/java/com/itsaky/androidide/adapters/DiagnosticItemAdpater.java @@ -8,10 +8,10 @@ import androidx.recyclerview.widget.RecyclerView; import com.itsaky.androidide.R; import com.itsaky.androidide.databinding.LayoutDiagnosticItemBinding; import com.itsaky.androidide.interfaces.DiagnosticClickListener; -import com.itsaky.lsp.Diagnostic; -import com.itsaky.lsp.DiagnosticSeverity; -import java.util.List; import java.io.File; +import java.util.List; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; public class DiagnosticItemAdpater extends RecyclerView.Adapter { @@ -36,8 +36,8 @@ public class DiagnosticItemAdpater extends RecyclerView.Adapter { if(listener != null) { @@ -52,7 +52,7 @@ public class DiagnosticItemAdpater extends RecyclerView.Adapter serveralisteners = new ArrayList<>(); - public static final boolean DEBUG = com.itsaky.androidide.BuildConfig.DEBUG; public static final long BUSYBOX_VERSION = 1; @@ -169,14 +155,6 @@ public class StudioApp extends MultiDexApplication public void createCompletionService() { this.mXmlCompletionService = new XMLCompletionService(); } - - public void setJavaLanguageServer(JavaLanguageServer server) { - this.languageServer = server; - } - - public JavaLanguageServer getJavaLanguageServer() { - return languageServer; - } public XMLCompletionService getXmlCompletionService() { return mXmlCompletionService; @@ -209,18 +187,6 @@ public class StudioApp extends MultiDexApplication return shellServer; } - public void addServerListener(LanguageServerListener listener) { - if(serveralisteners == null) serveralisteners = new ArrayList<>(); - if(!serveralisteners.contains(listener)) - serveralisteners.add(listener); - } - - public void removeServerListener(LanguageServerListener listener) { - if(serveralisteners == null) serveralisteners = new ArrayList<>(); - if(serveralisteners.contains(listener)) - serveralisteners.remove(listener); - } - public void writeException(Throwable th) { FileUtil.writeFile(new File(FileUtil.getExternalStorageDir(), "idelog.txt").getAbsolutePath(), ThrowableUtils.getFullStackTrace(th)); } diff --git a/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java index cbfc40b5a..f066beb01 100644 --- a/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java +++ b/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java @@ -9,10 +9,8 @@ import com.blankj.utilcode.util.SizeUtils; import com.itsaky.androidide.adapters.CompletionListAdapter; import com.itsaky.androidide.databinding.FragmentEditorBinding; import com.itsaky.androidide.fragments.preferences.EditorPreferences; -import com.itsaky.androidide.interfaces.JLSRequestor; import com.itsaky.androidide.language.groovy.GroovyLanguage; import com.itsaky.androidide.language.java.JavaLanguage; -import com.itsaky.androidide.language.java.JavaLanguageAnalyzer; import com.itsaky.androidide.language.xml.XMLLanguage; import com.itsaky.androidide.language.xml.lexer.XMLLexer; import com.itsaky.androidide.managers.PreferenceManager; @@ -21,30 +19,21 @@ import com.itsaky.androidide.models.ConstantsBridge; import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE; import com.itsaky.androidide.tasks.TaskExecutor; import com.itsaky.androidide.tasks.callables.ReadFileTask; +import com.itsaky.androidide.utils.LSPUtils; import com.itsaky.androidide.utils.TypefaceUtils; -import com.itsaky.lsp.CodeAction; -import com.itsaky.lsp.Diagnostic; -import com.itsaky.lsp.DidSaveTextDocumentParams; -import com.itsaky.lsp.JavaColors; -import com.itsaky.lsp.Position; -import com.itsaky.lsp.Range; -import com.itsaky.lsp.TextDocumentIdentifier; -import com.itsaky.lsp.TextDocumentPositionParams; -import com.itsaky.lsp.TextEdit; import io.github.rosemoe.editor.interfaces.EditorEventListener; import io.github.rosemoe.editor.langs.EmptyLanguage; import io.github.rosemoe.editor.widget.CodeEditor; import java.io.File; import java.io.StringReader; -import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.Token; -import io.github.rosemoe.editor.text.Content; -import com.itsaky.androidide.utils.LSPUtils; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.Range; public class EditorFragment extends BaseFragment implements EditorEventListener { @@ -56,11 +45,8 @@ public class EditorFragment extends BaseFragment implements EditorEventListener private ModificationStateListener mModificationStateListener; private FileOpenListener mOpenListener; - private JLSRequestor mJLSRequestor; private static AndroidProject mProject; - private JavaLanguage mJavaLanguage; - public static final String KEY_FILE_PATH = "file_path"; public static final String KEY_PROJECT = "project"; public static final String KEY_LINE_START = "line_start"; @@ -76,11 +62,6 @@ public class EditorFragment extends BaseFragment implements EditorEventListener public static final String EXT_KOTLIN = ".kt"; public static final String EXT_JSON = ".json"; - public EditorFragment setJLSRequestor(JLSRequestor requestor) { - this.mJLSRequestor = requestor; - return this; - } - public EditorFragment setModificationStateListener(ModificationStateListener listener) { this.mModificationStateListener = listener; return this; @@ -97,14 +78,6 @@ public class EditorFragment extends BaseFragment implements EditorEventListener return ""; } - public void setJavaColors(JavaColors colors) { - if(mJavaLanguage != null) { - JavaLanguageAnalyzer analyzer = (JavaLanguageAnalyzer) mJavaLanguage.getAnalyzer(); - analyzer.setJavaColors(colors); - mBinding.editor.notifySpansChanged(); - } - } - public static EditorFragment newInstance(File file, AndroidProject project, org.eclipse.lsp4j.Range selection) { Bundle bundle = new Bundle(); bundle.putString(KEY_FILE_PATH, file.getAbsolutePath()); @@ -161,7 +134,6 @@ public class EditorFragment extends BaseFragment implements EditorEventListener mBinding.editor.setAutoCompletionItemAdapter(new CompletionListAdapter()); mBinding.editor.setLineColorsEnabled(true); mBinding.editor.setDividerWidth(SizeUtils.dp2px(1)); - mBinding.editor.setJLSRequestor(mJLSRequestor); configureEditorIfNeeded(); @@ -202,7 +174,7 @@ public class EditorFragment extends BaseFragment implements EditorEventListener for(int i=0;i 0 && name.length() <= 40 && FileUtils.rename(f, name); activity(). getApp().toast(renamed ? R.string.renamed : R.string.rename_failed, renamed ? Toaster.Type.SUCCESS : Toaster.Type.ERROR); if(renamed) { + LSP.notifyFileRenamed(f, name); if(activity().getLastHoldTreeNode() != null) { TreeNode parent = activity().getLastHoldTreeNode().getParent(); parent.deleteChild(activity().getLastHoldTreeNode()); diff --git a/app/src/main/java/com/itsaky/androidide/handlers/IDEHandler.java b/app/src/main/java/com/itsaky/androidide/handlers/IDEHandler.java index 30a5bd7eb..d0eef31d6 100644 --- a/app/src/main/java/com/itsaky/androidide/handlers/IDEHandler.java +++ b/app/src/main/java/com/itsaky/androidide/handlers/IDEHandler.java @@ -4,7 +4,6 @@ import com.itsaky.androidide.EditorActivity; import com.itsaky.androidide.models.AndroidProject; import com.itsaky.androidide.models.project.IDEProject; import com.itsaky.androidide.utils.Logger; -import com.itsaky.androidide.handlers.jls.JLSHandler; /** * A handler is an implementation that handles a specific feature, data or anything else in AndroidIDE @@ -27,10 +26,6 @@ public abstract class IDEHandler { return provider.provideEditorActivity(); } - protected JLSHandler jls() { - return provider.provideJLSHandler(); - } - protected AndroidProject androidProject() { return provider.provideAndroidProject(); } @@ -68,12 +63,5 @@ public abstract class IDEHandler { * @throws NullPointerException is this is required */ IDEProject provideIDEProject(); - - /** - * Called by handler to get a reference of the current {@link IDEProject} - * - * @throws NullPointerException is this is required - */ - JLSHandler provideJLSHandler(); } } diff --git a/app/src/main/java/com/itsaky/androidide/handlers/jls/JLSHandler.java b/app/src/main/java/com/itsaky/androidide/handlers/jls/JLSHandler.java deleted file mode 100644 index 53df45e50..000000000 --- a/app/src/main/java/com/itsaky/androidide/handlers/jls/JLSHandler.java +++ /dev/null @@ -1,322 +0,0 @@ -package com.itsaky.androidide.handlers.jls; - -import android.text.TextUtils; -import android.view.View; -import com.blankj.utilcode.util.FileIOUtils; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.gson.Gson; -import com.itsaky.androidide.EditorActivity; -import com.itsaky.androidide.R; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.fragments.EditorFragment; -import com.itsaky.androidide.handlers.IDEHandler; -import com.itsaky.androidide.interfaces.JLSRequestor; -import com.itsaky.androidide.language.java.server.JavaLanguageServer; -import com.itsaky.androidide.models.AndroidProject; -import com.itsaky.lsp.CodeAction; -import com.itsaky.lsp.DidChangeTextDocumentParams; -import com.itsaky.lsp.DidChangeWatchedFilesParams; -import com.itsaky.lsp.DidCloseTextDocumentParams; -import com.itsaky.lsp.DidOpenTextDocumentParams; -import com.itsaky.lsp.DidSaveTextDocumentParams; -import com.itsaky.lsp.FileChangeType; -import com.itsaky.lsp.FileEvent; -import com.itsaky.lsp.LanguageClient; -import com.itsaky.lsp.Range; -import com.itsaky.lsp.ReferenceParams; -import com.itsaky.lsp.TextDocumentPositionParams; -import com.itsaky.lsp.TextEdit; -import io.github.rosemoe.editor.text.Content; -import java.io.File; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -public class JLSHandler extends IDEHandler implements JLSRequestor { - - private JavaLanguageServer languageServer; - - private final LanguageClientHandler client; - private static final Gson gson = new Gson(); - - public JLSHandler(LanguageClientHandler client, Provider provider) { - super(provider); - this.client = client; - } - - public JavaLanguageServer getJLS() { - return languageServer; - } - - @Override - public void start() { - if(activity() == null) { - throw new NullPointerException("EditorActivity should not be null"); - } - - AndroidProject project = provider.provideAndroidProject(); - if(project == null) { - throw new NullPointerException("Project is null"); - } - - this.client.start(); - - this.languageServer = new JavaLanguageServer(project, this.client); -// this.languageServer.startServer(); - - StudioApp.getInstance().setJavaLanguageServer(languageServer); - } - - @Override - public void stop() { - if(languageServer != null) - languageServer.exit(); - } - - @Override - public void hideSignature() { - activity().getBinding().symbolText.setVisibility(View.GONE); - } - - @Override - public void didOpen(DidOpenTextDocumentParams p) { - if(languageServer != null) - languageServer.didOpen(p); - else activity().addPendingMessage(activity().createMessage(JavaLanguageServer.Method.DID_OPEN, gson.toJson(p))); - } - - @Override - public void didClose(DidCloseTextDocumentParams p) { - if(languageServer != null) - languageServer.didClose(p); - else activity().addPendingMessage(activity().createMessage(JavaLanguageServer.Method.DID_CLOSE, gson.toJson(p))); - } - - @Override - public void didChange(DidChangeTextDocumentParams params) { - if(languageServer != null) - languageServer.didChange(params); - else activity().addPendingMessage(activity().createMessage(JavaLanguageServer.Method.DID_CHANGE, gson.toJson(params))); - } - - @Override - public void didSave(DidSaveTextDocumentParams params) { - if(languageServer != null) - languageServer.didSave(params); - else activity().addPendingMessage(activity().createMessage(JavaLanguageServer.Method.DID_SAVE, gson.toJson(params))); - } - - @Override - public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) { - if(languageServer != null) - languageServer.didChangeWatchedFiles(params); - else activity().addPendingMessage(activity().createMessage(JavaLanguageServer.Method.DID_SAVE, gson.toJson(params))); - } - - @Override - public void signatureHelp(TextDocumentPositionParams params, File file) { - if(languageServer != null) - languageServer.signatureHelp(params, file); - else activity().addPendingMessage(activity().createMessage(JavaLanguageServer.Method.DID_SAVE, gson.toJson(params))); - } - - @Override - public void findDefinition(TextDocumentPositionParams params) { - if(languageServer == null || !languageServer.isStarted()) return; - languageServer.findDefinition(params); - activity().getProgressSheet(R.string.msg_finding_definition).show(activity().getSupportFragmentManager(), "definition_progress"); - } - - @Override - public void findReferences(ReferenceParams params) { - if(languageServer == null || !languageServer.isStarted()) return; - languageServer.findReferences(params); - activity().getProgressSheet(R.string.msg_finding_references).show(activity().getSupportFragmentManager(), "references_progress"); - } - - @Override - public void performCodeActions(final File file, List actions) { - final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity(), R.style.AppTheme_MaterialAlertDialog); - builder.setTitle(R.string.msg_code_actions); - builder.setItems(mapActionsAsArray(removeDuplicates(actions)), (d, w) -> { - d.dismiss(); - int index = w; - confirmActionIfNecessary(file, actions.get(index)); - }); - builder.setCancelable(true); - builder.show(); - } - - /** - * Shows a dialog to user to get confirmation from user to modify files other than this one - * If the code action is only in the current file, directly performs the actions - */ - private void confirmActionIfNecessary(File file, CodeAction action) { - if(isInSameFile(file, action.edit.changes)) { - performCodeAction(file, action); - } else { - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity(), R.style.AppTheme_MaterialAlertDialog); - builder.setTitle(R.string.title_confirm_changes); - builder.setMessage(activity().getString(R.string.msg_confirm_changes, getFileNamesOfEdits(action.edit.changes.keySet()))); - builder.setPositiveButton(android.R.string.yes, (d, w) -> performCodeAction(file, action)); - builder.setNegativeButton(android.R.string.no, null); - builder.show(); - } - } - - private String getFileNamesOfEdits(Set names) { - return TextUtils.join("\n", names.stream().filter(n -> n != null).map(File::new).collect(Collectors.toList())); - } - - /** - * Some code actions may contain duplicate items
- * Removes duplicate CodeActions from the given list - * - * @param actions CodeActions to filter - */ - private List removeDuplicates(List actions) { - List filtered = new ArrayList<>(); - for(CodeAction action : actions) { - if(filtered.contains(action)) continue; - - filtered.add(action); - } - return filtered; - } - - private CharSequence[] mapActionsAsArray(List actions) { - String[] result = new String[actions.size()]; - for(int i=0;i> changes = action.edit.changes; - - /** - * TODO: Ask for confirmation before writing file other than currently opened file - */ - for(Map.Entry> entry : changes.entrySet()) { - if(entry == null && entry.getKey() == null || entry.getValue() == null) continue; - performEdits(new File(entry.getKey()), entry.getValue()); - } - } - } - - /** - * Performs edits in specified file. If the file is already opened, - * it will find the EditorFragment containing this file and perform the edits in its Content - *

- * If the file is not opened, it will read that file, edit it accordingly and will save it. - * - * @param file The file to edit - * @param edits The edits to perform - */ - public void performEdits(File file, List edits) { - if(edits == null || edits.size() <= 0) return; - - boolean wroteInFragment = false; - - if(activity().getPagerAdapter() != null) { - EditorFragment frag = activity().getPagerAdapter().findEditorByFile(file); - if(frag != null && frag.getEditor() != null && frag.getEditor().getText() != null) { - performEdits(frag.getEditor().getText(), edits); - wroteInFragment = true; - } - } - - if(!wroteInFragment) { - readAndPerformEdits(file, edits); - } - } - - /** - * Performs given text edits in provided content - * - * @param text Content to edit - * @param edits The edits to perform - */ - private void performEdits(Content text, List edits) { - for(TextEdit edit : edits) { - if(edit == null) continue; - if(edit.newText == null || edit.range == null) continue; - final Range range = edit.range; - text.replace( - range.start.line, - range.start.column, - range.end.line, - range.end.column, - edit.newText - ); - } - } - - /** - * Reads the provided file and performs the given edits - * - * @param file The file to read - * @param edits Edits to perform - */ - private void readAndPerformEdits(File file, List edits) { - String text = FileIOUtils.readFile2String(file); - if(text == null || text.length() <= 0) return; - Content content = new Content(null, text); - performEdits(content, edits); - - FileIOUtils.writeFileFromString(file, content.toString()); - - notifyFileChanged(file); - } - - /** - * Checks if all the changes are in the same (currently opened) file - * - * @param current File to check - * @param changes The changes to check - * @return Whether all changes are in the currently opened file - */ - private boolean isInSameFile(File current, Map> changes) { - for(URI uri : changes.keySet()) { - File file = new File(uri); - if(file.exists() - && !file.getAbsolutePath().equals(current.getAbsolutePath())) { - return false; - } - } - return true; - } - - public void notifyFileCreated(File file) { - notifyExternalFileChange(file, FileChangeType.Created); - - activity().openFile(file); - } - - public void notifyFileDeleted(File file) { - notifyExternalFileChange(file, FileChangeType.Deleted); - } - - public void notifyFileChanged(File file) { - notifyExternalFileChange(file, FileChangeType.Changed); - } - - private void notifyExternalFileChange(File file, int changeType) { - if(!file.getName().endsWith(".java")) return; - DidChangeWatchedFilesParams p = new DidChangeWatchedFilesParams(); - p.changes.add(new FileEvent(file.toURI(), changeType)); - didChangeWatchedFiles(p); - } -} diff --git a/app/src/main/java/com/itsaky/androidide/handlers/jls/LanguageClientHandler.java b/app/src/main/java/com/itsaky/androidide/handlers/jls/LanguageClientHandler.java deleted file mode 100644 index e33990288..000000000 --- a/app/src/main/java/com/itsaky/androidide/handlers/jls/LanguageClientHandler.java +++ /dev/null @@ -1,254 +0,0 @@ -package com.itsaky.androidide.handlers.jls; - -import android.text.SpannableStringBuilder; -import android.text.style.ForegroundColorSpan; -import android.view.View; -import com.blankj.utilcode.util.FileIOUtils; -import com.blankj.utilcode.util.ThrowableUtils; -import com.google.gson.JsonElement; -import com.itsaky.androidide.R; -import com.itsaky.androidide.adapters.DiagnosticsAdapter; -import com.itsaky.androidide.adapters.SearchListAdapter; -import com.itsaky.androidide.fragments.EditorFragment; -import com.itsaky.androidide.handlers.IDEHandler; -import com.itsaky.androidide.language.java.server.JavaLanguageServer; -import com.itsaky.androidide.models.DiagnosticGroup; -import com.itsaky.androidide.models.SearchResult; -import com.itsaky.lsp.Diagnostic; -import com.itsaky.lsp.JavaColors; -import com.itsaky.lsp.JavaReportProgressParams; -import com.itsaky.lsp.JavaStartProgressParams; -import com.itsaky.lsp.LanguageClient; -import com.itsaky.lsp.Location; -import com.itsaky.lsp.Message; -import com.itsaky.lsp.ParameterInformation; -import com.itsaky.lsp.PublishDiagnosticsParams; -import com.itsaky.lsp.ShowMessageParams; -import com.itsaky.lsp.SignatureHelp; -import com.itsaky.lsp.SignatureInformation; -import com.itsaky.toaster.Toaster; -import io.github.rosemoe.editor.text.Content; -import io.github.rosemoe.editor.widget.CodeEditor; -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class LanguageClientHandler extends IDEHandler implements LanguageClient { - - private final Map> diagnostics = new HashMap<>(); - - public LanguageClientHandler(Provider provider) { - super(provider); - } - - @Override - public void start() { - // Unimplemented - } - - @Override - public void stop() { - // Unimplemented - } - - @Override - public void publishDiagnostics(PublishDiagnosticsParams params) { - boolean error = params == null || params.diagnostics == null || params.diagnostics.size() <= 0; - activity().handleDiagnosticsResultVisibility(error); - - if(error) return; - - File file = new File(params.uri); - if(!(file.exists() && file.isFile())) return; - - diagnostics.put(file, params.diagnostics); - activity().getDiagnosticsList().setAdapter(newDiagnosticsAdapter()); - - EditorFragment editor = null; - if(activity().getPagerAdapter() != null && (editor = activity().getPagerAdapter().findEditorByFile(new File(params.uri))) != null) { - editor.setDiagnostics(params.diagnostics); - } - } - - @Override - public void gotoDefinition(List locations) { - if(activity().getProgressSheet() != null && activity().getProgressSheet().isShowing()) - activity().getProgressSheet().dismiss(); - if(locations == null || locations.size() <= 0) { - activity().getApp().toast(R.string.msg_no_definition, Toaster.Type.ERROR); - return; - } - - } - - @Override - public void references(List references) { - if(activity().getProgressSheet() != null && activity().getProgressSheet().isShowing()) - activity().getProgressSheet().dismiss(); - - boolean error = references == null || references.size() <= 0; - activity().handleSearchResultVisibility(error); - - - if(error) { - activity().getApp().toast(R.string.msg_no_references, Toaster.Type.INFO); - activity().getSearchResultList().setAdapter(new SearchListAdapter(null, null, null)); - return; - } - - final Map> results = new HashMap<>(); -// for(int i=0;i matches = results.containsKey(file) ? results.get(file) : new ArrayList<>(); -// matches.add( -// new SearchResult( -// loc.range, -// file, -// content.getLineString(loc.range.start.line), -// content.subContent( -// loc.range.start.line, -// loc.range.start.column, -// loc.range.end.line, -// loc.range.end.column -// ).toString() -// ) -// ); -// results.put(file, matches); -// } catch (Throwable th) { -// LOG.error(ThrowableUtils.getFullStackTrace(th)); -// } -// } - - activity().handleSearchResults(results); - } - - @Override - public void signatureHelp(SignatureHelp signature, File file) { - if(signature == null || signature.signatures == null) { - activity().getBinding().symbolText.setVisibility(View.GONE); - return; - } - SignatureInformation info = signature.signatures.get(signature.activeSignature); - activity().getBinding().symbolText.setText(formatSignature(info, signature.activeParameter)); - final EditorFragment frag = activity().getPagerAdapter().findEditorByFile(file); - if(frag != null) { - final CodeEditor editor = frag.getEditor(); - final float[] cursor = editor.getCursorPosition(); - - float x = editor.updateCursorAnchor() - (activity().getBinding().symbolText.getWidth() / 2); - float y = activity().getBinding().editorAppBarLayout.getHeight() + (cursor[0] - editor.getRowHeight() - editor.getOffsetY() - activity().getBinding().symbolText.getHeight()); - activity().getBinding().symbolText.setVisibility(View.VISIBLE); - activity().positionViewWithinScreen(activity().getBinding().symbolText, x, y); - } - } - - @Override - public void javaColors(JavaColors colors) { - final File file = new File(colors.uri); - final EditorFragment editor = this.activity().getPagerAdapter().findEditorByFile(file); - if(editor != null) - editor.setJavaColors(colors); - } - - @Override - public void onServerStarted(int currentId) { - new Thread(() -> { - final JavaLanguageServer server = provider.provideJLSHandler().getJLS(); - while(server != null && !activity().pendingMessages.isEmpty()) { - Message msg = activity().pendingMessages.pop(); - server.send(msg); - } - }).start(); - } - - public DiagnosticsAdapter newDiagnosticsAdapter() { - return new DiagnosticsAdapter(mapAsGroup(this.diagnostics), activity()); - } - - /** - * Formats (highlights) a method signature - * - * @param signature Signature information - * @param paramIndex Currently active parameter index - */ - private CharSequence formatSignature(SignatureInformation signature, int paramIndex) { - String name = signature.label; - name = name.substring(0, name.indexOf("(")); - - SpannableStringBuilder sb = new SpannableStringBuilder(); - sb.append(name, new ForegroundColorSpan(0xffffffff), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); - sb.append("(", new ForegroundColorSpan(0xff4fc3f7), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); - - List params = signature.parameters; - for(int i=0;i mapAsGroup(Map> diags) { - List groups = new ArrayList<>(); - if(diags == null || diags.size() <= 0) - return groups; - for(File file : diags.keySet()) { - List fileDiags = diags.get(file); - if(fileDiags == null || fileDiags.size() <= 0) - continue; - DiagnosticGroup group = new DiagnosticGroup(R.drawable.ic_language_java, file, fileDiags); - groups.add(group); - } - return groups; - } - - - - - - /** - * NOT IMPLEMENTED - */ - - @Override - public void javaProgressStart(JavaStartProgressParams params) { - } - - @Override - public void javaProgressReport(JavaReportProgressParams params) { - } - - @Override - public void javaProgressEnd() { - } - - @Override - public void showMessage(ShowMessageParams params) { - } - - @Override - public void customNotification(String method, JsonElement params) { - } - - @Override - public void registerCapability(String method, JsonElement options) { - } -} diff --git a/app/src/main/java/com/itsaky/androidide/interfaces/DiagnosticClickListener.java b/app/src/main/java/com/itsaky/androidide/interfaces/DiagnosticClickListener.java index 3e6674fd1..e5dc16431 100644 --- a/app/src/main/java/com/itsaky/androidide/interfaces/DiagnosticClickListener.java +++ b/app/src/main/java/com/itsaky/androidide/interfaces/DiagnosticClickListener.java @@ -1,8 +1,8 @@ package com.itsaky.androidide.interfaces; import com.itsaky.androidide.models.DiagnosticGroup; -import com.itsaky.lsp.Diagnostic; import java.io.File; +import org.eclipse.lsp4j.Diagnostic; public interface DiagnosticClickListener { void onGroupClick(DiagnosticGroup group); diff --git a/app/src/main/java/com/itsaky/androidide/interfaces/JLSRequestor.java b/app/src/main/java/com/itsaky/androidide/interfaces/JLSRequestor.java deleted file mode 100644 index aaa875bfb..000000000 --- a/app/src/main/java/com/itsaky/androidide/interfaces/JLSRequestor.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.itsaky.androidide.interfaces; - -import com.itsaky.lsp.CodeAction; -import com.itsaky.lsp.DidChangeTextDocumentParams; -import com.itsaky.lsp.DidChangeWatchedFilesParams; -import com.itsaky.lsp.DidCloseTextDocumentParams; -import com.itsaky.lsp.DidOpenTextDocumentParams; -import com.itsaky.lsp.DidSaveTextDocumentParams; -import com.itsaky.lsp.ReferenceParams; -import com.itsaky.lsp.TextDocumentPositionParams; -import java.io.File; -import java.util.List; - -public interface JLSRequestor { - - void hideSignature(); - - void didOpen(DidOpenTextDocumentParams params); - void didClose(DidCloseTextDocumentParams params); - void didChange(DidChangeTextDocumentParams params); - void didSave(DidSaveTextDocumentParams params); - void didChangeWatchedFiles(DidChangeWatchedFilesParams params); - - void signatureHelp(TextDocumentPositionParams params, File file); - void findDefinition(TextDocumentPositionParams params); - void findReferences(ReferenceParams params); - void performCodeActions(File file, List actions); -} diff --git a/app/src/main/java/com/itsaky/androidide/interfaces/LanguageServerListener.java b/app/src/main/java/com/itsaky/androidide/interfaces/LanguageServerListener.java deleted file mode 100644 index a9b298305..000000000 --- a/app/src/main/java/com/itsaky/androidide/interfaces/LanguageServerListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.itsaky.androidide.interfaces; - -public interface LanguageServerListener -{ -} diff --git a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java index 099471a9b..69b7e457d 100644 --- a/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java +++ b/app/src/main/java/com/itsaky/androidide/language/groovy/GroovyAutoComplete.java @@ -1,17 +1,13 @@ package com.itsaky.androidide.language.groovy; -import com.itsaky.androidide.models.GradleSuggestItem; -import com.itsaky.androidide.models.SuggestItem; import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; import io.github.rosemoe.editor.text.TextAnalyzeResult; -import io.github.rosemoe.editor.widget.CodeEditor; import java.util.ArrayList; import java.util.List; import java.util.Locale; import org.eclipse.lsp4j.CompletionItem; -import org.eclipse.lsp4j.jsonrpc.messages.Either; -import org.eclipse.lsp4j.InsertTextFormat; import org.eclipse.lsp4j.CompletionItemKind; +import org.eclipse.lsp4j.InsertTextFormat; public class GroovyAutoComplete implements AutoCompleteProvider { diff --git a/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java index 540016cc7..0ef5aa62d 100644 --- a/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java +++ b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java @@ -3,7 +3,6 @@ package com.itsaky.androidide.language.java; import com.itsaky.androidide.utils.Logger; import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; import io.github.rosemoe.editor.text.TextAnalyzeResult; -import io.github.rosemoe.editor.widget.CodeEditor; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -16,20 +15,15 @@ import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.LanguageServer; -import com.itsaky.androidide.utils.JSONUtility; +import com.itsaky.androidide.lsp.LSPProvider; public class JavaAutoComplete implements AutoCompleteProvider { - private JavaLanguage language; private CompletableFuture, CompletionList>> future; - - public JavaAutoComplete(JavaLanguage lang) { - this.language = lang; - } @Override public List getAutoCompleteItems(String fileUri, String prefix, boolean isInCodeBlock, TextAnalyzeResult colors, int index, int line, int column) throws Exception { - LanguageServer languageServer = language.getLanguageServer(); + LanguageServer languageServer = LSPProvider.getServerForLanguage(LSPProvider.LANGUAGE_JAVA); if(languageServer != null && fileUri != null) { if(future != null && !future.isDone()) future.cancel(true); @@ -50,7 +44,6 @@ public class JavaAutoComplete implements AutoCompleteProvider { return sort(either.getRight().getItems()); } catch (Throwable th) { - LOG.error("Java completion error: ", th); // Ignore this exception. An empty list will be sent after this // This exeption is thrown probably because the request was cancelled or interrupted } diff --git a/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguage.java b/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguage.java index a78834d06..767d91ab2 100644 --- a/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguage.java +++ b/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguage.java @@ -5,7 +5,6 @@ import com.itsaky.androidide.language.java.manager.JavaCharacter; import com.itsaky.androidide.language.java.parser.JavaLexer; import com.itsaky.androidide.language.java.parser.JavaParser; import com.itsaky.androidide.lsp.LSPProvider; -import com.itsaky.androidide.models.AndroidProject; import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; import io.github.rosemoe.editor.interfaces.CodeAnalyzer; import io.github.rosemoe.editor.interfaces.NewlineHandler; @@ -18,14 +17,12 @@ import org.eclipse.lsp4j.services.LanguageServer; public class JavaLanguage extends BaseLanguage { - private JavaLanguageAnalyzer analyzer; - private JavaAutoComplete complete; - private AndroidProject project; + private final JavaLanguageAnalyzer analyzer; + private final JavaAutoComplete complete; - public JavaLanguage(AndroidProject project) { + public JavaLanguage() { this.analyzer = new JavaLanguageAnalyzer(); - this.complete = new JavaAutoComplete(this); - this.project = project; + this.complete = new JavaAutoComplete(); } @Override diff --git a/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguageAnalyzer.java b/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguageAnalyzer.java index 9acae5c3d..6bfc04271 100644 --- a/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguageAnalyzer.java +++ b/app/src/main/java/com/itsaky/androidide/language/java/JavaLanguageAnalyzer.java @@ -1,22 +1,16 @@ package com.itsaky.androidide.language.java; import com.itsaky.androidide.syntax.lexer.impls.java.JavaLexerImpl; -import com.itsaky.lsp.Range; import io.github.rosemoe.editor.interfaces.CodeAnalyzer; import io.github.rosemoe.editor.text.TextAnalyzeResult; import io.github.rosemoe.editor.text.TextAnalyzer; -import java.util.List; -import com.itsaky.lsp.JavaColors; public class JavaLanguageAnalyzer implements CodeAnalyzer { - private JavaColors colors; - @Override public void analyze(CharSequence content, TextAnalyzeResult colors, TextAnalyzer.AnalyzeThread.Delegate delegate) { try { JavaLexerImpl lexer = new JavaLexerImpl(content.toString(), colors); - lexer.setJavaColors(this.colors); lexer.init(); // Adding spans, hex colors, block lines and all is handled by JavaLexerImpl @@ -34,8 +28,4 @@ public class JavaLanguageAnalyzer implements CodeAnalyzer { } catch (Throwable e) { } } - - public void setJavaColors(JavaColors colors) { - this.colors = colors; - } } diff --git a/app/src/main/java/com/itsaky/androidide/language/java/server/JavaLanguageServer.java b/app/src/main/java/com/itsaky/androidide/language/java/server/JavaLanguageServer.java deleted file mode 100644 index 1e9cf3511..000000000 --- a/app/src/main/java/com/itsaky/androidide/language/java/server/JavaLanguageServer.java +++ /dev/null @@ -1,429 +0,0 @@ -package com.itsaky.androidide.language.java.server; - -import android.annotation.SuppressLint; -import androidx.core.util.Pair; -import com.blankj.utilcode.util.ThreadUtils; -import com.blankj.utilcode.util.ThrowableUtils; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.reflect.TypeToken; -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.models.AndroidProject; -import com.itsaky.androidide.shell.ShellServer; -import com.itsaky.androidide.utils.Environment; -import com.itsaky.androidide.utils.Logger; -import com.itsaky.lsp.CancelParams; -import com.itsaky.lsp.CodeActionParams; -import com.itsaky.lsp.CompletionItem; -import com.itsaky.lsp.CompletionList; -import com.itsaky.lsp.DidChangeConfigurationParams; -import com.itsaky.lsp.DidChangeTextDocumentParams; -import com.itsaky.lsp.DidChangeWatchedFilesParams; -import com.itsaky.lsp.DidCloseTextDocumentParams; -import com.itsaky.lsp.DidOpenTextDocumentParams; -import com.itsaky.lsp.DidSaveTextDocumentParams; -import com.itsaky.lsp.DocumentFormattingParams; -import com.itsaky.lsp.InitializeParams; -import com.itsaky.lsp.JavaColors; -import com.itsaky.lsp.JavaReportProgressParams; -import com.itsaky.lsp.JavaStartProgressParams; -import com.itsaky.lsp.LanguageClient; -import com.itsaky.lsp.Location; -import com.itsaky.lsp.Message; -import com.itsaky.lsp.PublishDiagnosticsParams; -import com.itsaky.lsp.ReferenceParams; -import com.itsaky.lsp.SignatureHelp; -import com.itsaky.lsp.TextDocumentPositionParams; -import com.itsaky.lsp.TextEdit; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.Socket; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; - -public class JavaLanguageServer implements ShellServer.Callback { - - private AndroidProject project; - private ShellServer shell; - - private LanguageClient client; - private Socket server; - private BufferedOutputStream send; - - private boolean started; - - private final ConcurrentHashMap completionRequests = new ConcurrentHashMap<>(); - private final ConcurrentHashMap formattingRequests = new ConcurrentHashMap<>(); - private final ConcurrentHashMap definitionRequests = new ConcurrentHashMap<>(); - private final ConcurrentHashMap referencesRequests = new ConcurrentHashMap<>(); - private final ConcurrentHashMap codeActionRequests = new ConcurrentHashMap<>(); - private final ConcurrentHashMap signatureRequests = new ConcurrentHashMap<>(); - - private final BlockingQueue completionResponseQueue = new ArrayBlockingQueue<>(20); - - private static final String START_COMMAND = "java " + - "--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED " + - "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED " + - "--add-exports jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED " + - "--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED " + - "--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED " + - "--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED " + - "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED " + - "--add-opens jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED " + - "-cp $JLS_HOME/lib/jls.jar:$JLS_HOME/lib/gson.jar:$JLS_HOME/lib/protobuf.jar " + - "org.javacs.Main"; - - - private static final String CONTENT_LENGTH = "Content-Length: "; - private static final String SOCKET_HOST = "localhost"; - private static final int SOCKET_PORT = 5443; - private static int UNIVERSION_ID = 1; - private static final Gson gson = new Gson(); - - public JavaLanguageServer(AndroidProject project, LanguageClient client) { - this.project = project; - this.client = client; - this.shell = StudioApp.getInstance().newShell(this); - } - - public void startServer() { - this.shell.bgAppend(START_COMMAND); - - new Thread(() -> { - try { - Socket socket = connectAndGet(); - sendInit(); - BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); - String line; - while((line = reader.readLine()) != null) { - final String temp = line; - if(temp == null || temp.trim().length() <= 0) continue; - ThreadUtils.runOnUiThread(() -> { - onServerOut(temp); - }); - } - socket.close(); - LOG.info("Socket disconnected"); - } catch (Throwable e) { - logEx(e); - } - }).start(); - } - - public void initialize(AndroidProject project) { - this.project = project; - sendInit(); - } - - private Socket connectAndGet() { - while(server == null || send == null || !server.isConnected()) { - try { - server = new Socket(SOCKET_HOST, SOCKET_PORT); - OutputStream o = server.getOutputStream(); - if(o != null) - send = new BufferedOutputStream(o); - } catch (IOException e) { - try { - Thread.sleep(100); - } catch (InterruptedException e2) {} - } - } - return server; - } - - @SuppressLint("NewApi") - protected void sendInit() { - InitializeParams p = new InitializeParams(); - p.rootUri = new File(project.getProjectPath()).toURI(); - p.roots = java.util.Set.of(p.rootUri, StudioApp.getInstance().getLogSenderDir().toURI()); - initialize(p); - initialized(); - - final List cps = project.getClassPaths(); - if(!cps.contains(Environment.BOOTCLASSPATH.getAbsolutePath())) cps.add(Environment.BOOTCLASSPATH.getAbsolutePath()); - JsonObject settings = new JsonObject(); - JsonObject java = new JsonObject(); - JsonArray classpaths = new JsonArray(); - for(int i=0;i { - if(client != null) - client.onServerStarted(UNIVERSION_ID); - }); - } - - public void exit() { - write(Method.EXIT, ""); - try { - server.close(); - } catch (Throwable th) {} - } - - public boolean isStarted() { - return started; - } - - public void initialize(InitializeParams p) { - write(Method.INITIALIZE, gson.toJson(p)); - } - - public void initialized() { - write(Method.INITIALIZED, "{}"); - } - - public void configurationChanged(DidChangeConfigurationParams p) { - write(Method.CHANGED_CONFIGURATION, gson.toJson(p)); - } - - public void didOpen(DidOpenTextDocumentParams p) { - write(Method.DID_OPEN, gson.toJson(p)); - } - - public void didClose(DidCloseTextDocumentParams p) { - write(Method.DID_CLOSE, gson.toJson(p)); - } - - public void didChange(DidChangeTextDocumentParams p) { - write(Method.DID_CHANGE, gson.toJson(p)); - } - - public void didSave(DidSaveTextDocumentParams p) { - write(Method.DID_SAVE, gson.toJson(p)); - } - - public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) { - write(Method.CHANGED_WATCHED_FILES, gson.toJson(params)); - } - - public void buildModified() { - write(Method.BUILD_MODIFIED, ""); - } - - public Pair completion(TextDocumentPositionParams p) { - int id = write(Method.COMPLETION, gson.toJson(p)); - completionRequests.put(id, id); - CompletionList result = null; - try { - result = completionResponseQueue.take(); - } catch (InterruptedException e) {} - return Pair.create(id, result); - } - - public void resolveCompletion(CompletionItem item) { - write(Method.RESOLVE_COMPLETION, gson.toJson(item)); - } - - public List formatting(DocumentFormattingParams params) { - int id = write(Method.FORMATTING, gson.toJson(params)); - formattingRequests.put(id, id); - List edits = null; - return edits; - } - - public void codeActions(CodeActionParams p) { - int id = write(Method.CODE_ACTION, gson.toJson(p)); - codeActionRequests.put(id, id); - } - - public void signatureHelp(TextDocumentPositionParams params, File file) { - int id = write(Method.SIGNATURE_HELP, gson.toJson(params)); - signatureRequests.put(id, file); - } - - public void findDefinition(TextDocumentPositionParams params) { - int id = write(Method.DEFINITION, gson.toJson(params)); - definitionRequests.put(id, id); - } - - public void findReferences(ReferenceParams params) { - int id = write(Method.REFERENCES, gson.toJson(params)); - referencesRequests.put(id, id); - } - - public void cancelRequest(int requestId) { - CancelParams p = new CancelParams(); - p.id = requestId; - write(Method.CANCEL_REQUEST, gson.toJson(p)); - } - - public int send(Message msg) { - final int id = UNIVERSION_ID++; - msg.id = id; - if(this.send != null) { - // Message must end with a \n so that server can read it correctly - final String body = gson.toJson(msg) + "\n"; - final byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8); - new Thread(() -> { - try { - send.write(bodyBytes); - send.flush(); - } catch (Throwable e) { - LOG.error("Error writing to server: " + ThrowableUtils.getFullStackTrace(e)); - } - }).start(); - } - - return id; - } - - private int write(String method, String data) { - Message msg = new Message(); - msg.jsonrpc = "2.0"; - msg.method = method; - msg.params = new JsonParser().parse(data); - return send(msg); - } - - private void logEx(Throwable th) { - LOG.error(ThrowableUtils.getFullStackTrace(th)); - } - - @Override - public void output(CharSequence charSequence) { - LOG.verbose(charSequence); - } - - /** - * This method is called on UI Thread, do not perform time consuming or networking tasks - */ - private void onServerOut(String line) { - if(line.contains(CONTENT_LENGTH)) line = line.substring(0, line.lastIndexOf(CONTENT_LENGTH)); - if(this.client == null) return; - try { - JsonObject obj = new JsonParser().parse(line.trim()).getAsJsonObject(); - if(obj.has(Key.METHOD)) { - final String method = obj.get(Key.METHOD).getAsString(); - if(method.equals(Method.REGISTER_CAPABILITY)) { - started = true; - } else if(method.equals(Method.PUBLISH_DIAGNOSTICS)) { - LOG.debug(line); - PublishDiagnosticsParams params = gson.fromJson(obj.get(Key.PARAMS).toString(), PublishDiagnosticsParams.class); - client.publishDiagnostics(params); - } else if(method.equals(Method.JLS_PROGRESS_START)) { - JavaStartProgressParams params = gson.fromJson(obj.get(Key.PARAMS).toString(), JavaStartProgressParams.class); - client.javaProgressStart(params); - } else if(method.equals(Method.JLS_PROGRESS_REPORT)) { - JavaReportProgressParams params = gson.fromJson(obj.get(Key.PARAMS).toString(), JavaReportProgressParams.class); - client.javaProgressReport(params); - } else if(method.equals(Method.JLS_PROGRESS_END)) { - client.javaProgressEnd(); - } else if(method.equals(Method.JAVA_COLORS)) { - JavaColors colors = gson.fromJson(obj.get(Key.PARAMS).toString(), JavaColors.class); - client.javaColors(colors); - } - } else if(obj.has(Key.ID)) { - - if(obj.has(Key.ERROR)) { - /** - * We got an error - * TODO Handle this error - */ - return; - } - - final int id = obj.get(Key.ID).getAsInt(); - if(completionRequests.containsKey(id)) { - final CompletionList list = gson.fromJson(obj.get(Key.RESULT).getAsJsonObject(), CompletionList.class); - completionResponseQueue.put(list); - } else if(formattingRequests.containsKey(id)) { - // TODO: Implement this - } else if(signatureRequests.containsKey(id)) { - try { - SignatureHelp signature = gson.fromJson(obj.get(Key.RESULT).getAsJsonObject(), SignatureHelp.class); - client.signatureHelp(signature, signatureRequests.get(id)); - } catch ( Throwable th) { - client.signatureHelp(null, null); - } - } else if(definitionRequests.containsKey(id)) { - try { - final List locations = gson.fromJson(obj.get(Key.RESULT).getAsJsonArray(), new TypeToken>(){}.getType()); - client.gotoDefinition(locations); - } catch (Throwable th) { - client.gotoDefinition(null); - } - } else if(referencesRequests.containsKey(id)) { - try { - final List locations = gson.fromJson(obj.get(Key.RESULT).getAsJsonArray(), new TypeToken>(){}.getType()); - client.references(locations); - } catch (Throwable th) { - client.references(null); - } - } else if(codeActionRequests.containsKey(id)) { - // TODO: Implement code actions - } - } - } catch (Throwable th) {} - } - - private static final Logger LOG = Logger.instance("JavaLanguageServer"); - - public static class Method { - public static final String INITIALIZE = "initialize"; - public static final String INITIALIZED = "initialized"; - public static final String SHUTDOWN = "shutdown"; - public static final String EXIT = "exit"; - - public static final String BUILD_MODIFIED = "project/buildModified"; - - public static final String CHANGED_CONFIGURATION = "workspace/didChangeConfiguration"; - public static final String CHANGED_WATCHED_FILES = "workspace/didChangeWatchedFiles"; - - public static final String DID_OPEN = "textDocument/didOpen"; - public static final String DID_CLOSE = "textDocument/didClose"; - public static final String DID_CHANGE = "textDocument/didChange"; - public static final String DID_SAVE = "textDocument/didSave"; - public static final String WILL_SAVE = "textDocument/willSave"; - - public static final String COMPLETION = "textDocument/completion"; - public static final String RESOLVE_COMPLETION = "completionItem/resolve"; - - public static final String HOVER = "textDocument/hover"; - public static final String SIGNATURE_HELP = "textDocument/signatureHelp"; - public static final String DEFINITION = "textDocument/definition"; - public static final String REFERENCES = "textDocument/references"; - - public static final String PREPARE_RENAME = "textDocument/prepareRename"; - public static final String RENAME = "textDocument/rename"; - - public static final String FORMATTING = "textDocument/formatting"; - - public static final String CODE_ACTION = "textDocument/codeAction"; - - public static final String CANCEL_REQUEST = "$/cancelRequest"; - - public static final String JLS_PROGRESS_START = "java/startProgress"; - public static final String JLS_PROGRESS_REPORT = "java/reportProgress"; - public static final String JLS_PROGRESS_END = "java/endProgress"; - - public static final String PUBLISH_DIAGNOSTICS = "textDocument/publishDiagnostics"; - public static final String JAVA_COLORS = "java/colors"; - - public static final String REGISTER_CAPABILITY = "client/registerCapability"; - } - - public static class Key { - public static final String METHOD = "method"; - public static final String PARAMS = "params"; - public static final String ID = "id"; - public static final String RESULT = "result"; - - public static final String STATICS = "statics"; - public static final String FIELDS = "fields"; - - public static final String ERROR = "error"; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java index 8fc43ebaf..a709596c8 100644 --- a/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java +++ b/app/src/main/java/com/itsaky/androidide/language/xml/XMLAutoComplete.java @@ -2,18 +2,12 @@ package com.itsaky.androidide.language.xml; import com.itsaky.androidide.app.StudioApp; import com.itsaky.androidide.language.xml.completion.XMLCompletionService; -import com.itsaky.androidide.models.CompletionListItem; -import com.itsaky.androidide.models.SuggestItem; -import com.itsaky.androidide.utils.EitherOfResult; import io.github.rosemoe.editor.interfaces.AutoCompleteProvider; import io.github.rosemoe.editor.text.TextAnalyzeResult; -import io.github.rosemoe.editor.widget.CodeEditor; -import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.eclipse.lsp4j.CompletionItem; -import org.eclipse.lsp4j.jsonrpc.messages.Either; public class XMLAutoComplete implements AutoCompleteProvider { diff --git a/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClient.java b/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClient.java index 86be8a2e2..cc7bc7d80 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClient.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClient.java @@ -1,24 +1,44 @@ package com.itsaky.androidide.lsp; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.view.View; +import com.blankj.utilcode.util.FileIOUtils; import com.blankj.utilcode.util.FileUtils; +import com.blankj.utilcode.util.ThrowableUtils; import com.google.gson.Gson; import com.itsaky.androidide.EditorActivity; +import com.itsaky.androidide.R; +import com.itsaky.androidide.adapters.DiagnosticsAdapter; +import com.itsaky.androidide.adapters.SearchListAdapter; import com.itsaky.androidide.fragments.EditorFragment; import com.itsaky.androidide.interfaces.EditorActivityProvider; +import com.itsaky.androidide.models.DiagnosticGroup; +import com.itsaky.androidide.models.SearchResult; import com.itsaky.androidide.utils.LSPUtils; import com.itsaky.androidide.utils.Logger; +import io.github.rosemoe.editor.text.Content; +import io.github.rosemoe.editor.widget.CodeEditor; import java.io.File; import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink; +import org.eclipse.lsp4j.ParameterInformation; +import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.ShowDocumentParams; import org.eclipse.lsp4j.ShowDocumentResult; +import org.eclipse.lsp4j.SignatureHelp; +import org.eclipse.lsp4j.SignatureInformation; import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.lsp4j.services.LanguageServer; -import com.itsaky.androidide.utils.JSONUtility; /** * AndroidIDE specific implementation of the LanguageClient @@ -29,7 +49,8 @@ public abstract class IDELanguageClient implements LanguageClient { protected static final Logger LOG = Logger.instance("IDELanguageClient"); protected EditorActivityProvider activityProvider; - + + private final Map> diagnostics = new HashMap<>(); private final StarterListener starterListener; private final OnConnectedListener onConnectedListener; @@ -82,18 +103,118 @@ public abstract class IDELanguageClient implements LanguageClient { return activityProvider.provide(); } + @Override + public void publishDiagnostics(PublishDiagnosticsParams params) { + boolean error = params == null || params.getDiagnostics() == null || params.getDiagnostics().isEmpty(); + activity().handleDiagnosticsResultVisibility(error); + + if(error) return; + + File file = new File(URI.create(params.getUri())); + if(!file.exists() || !file.isFile()) return; + + diagnostics.put(file, params.getDiagnostics()); + activity().getDiagnosticsList().setAdapter(newDiagnosticsAdapter()); + + EditorFragment editor = null; + if(activity().getPagerAdapter() != null && (editor = activity().getPagerAdapter().findEditorByFile(new File(URI.create(params.getUri())))) != null) { + editor.setDiagnostics(params.getDiagnostics()); + } + } + /** - * Called by {@link io.github.rosemoe.editor.widget.CodeEditor CodeEditor} to show locations in EditorActivity + * Called by {@link io.github.rosemoe.editor.widget.CodeEditor CodeEditor} to show signature help in EditorActivity */ - public void showLocations(List locations) { - LOG.info("showLocations", JSONUtility.prettyPrinter.toJson(locations)); + public void showSignatureHelp(SignatureHelp signature, File file) { + if(signature == null || signature.getSignatures() == null) { + activity().getBinding().symbolText.setVisibility(View.GONE); + return; + } + SignatureInformation info = signature.getSignatures().get(signature.getActiveSignature()); + activity().getBinding().symbolText.setText(formatSignature(info, signature.getActiveParameter())); + final EditorFragment frag = activity().getPagerAdapter().findEditorByFile(file); + if(frag != null) { + final CodeEditor editor = frag.getEditor(); + final float[] cursor = editor.getCursorPosition(); + + float x = editor.updateCursorAnchor() - (activity().getBinding().symbolText.getWidth() / 2); + float y = activity().getBinding().editorAppBarLayout.getHeight() + (cursor[0] - editor.getRowHeight() - editor.getOffsetY() - activity().getBinding().symbolText.getHeight()); + activity().getBinding().symbolText.setVisibility(View.VISIBLE); + activity().positionViewWithinScreen(activity().getBinding().symbolText, x, y); + } } /** * Called by {@link io.github.rosemoe.editor.widget.CodeEditor CodeEditor} to show locations in EditorActivity */ + public void showLocations(List locations) { + + // Cannot show anything if the activity() is null + if(activity() == null) { + return; + } + + boolean error = locations == null || locations.isEmpty(); + activity().handleSearchResultVisibility(error); + + + if(error) { + activity().getSearchResultList().setAdapter(new SearchListAdapter(null, null, null)); + return; + } + + final Map> results = new HashMap<>(); + for(int i=0;i matches = results.containsKey(file) ? results.get(file) : new ArrayList<>(); + matches.add( + new SearchResult( + loc.getRange(), + file, + content.getLineString(loc.getRange().getStart().getLine()), + content.subContent( + loc.getRange().getStart().getLine(), + loc.getRange().getStart().getCharacter(), + loc.getRange().getEnd().getLine(), + loc.getRange().getEnd().getCharacter() + ).toString() + ) + ); + results.put(file, matches); + } catch (Throwable th) { + LOG.error(ThrowableUtils.getFullStackTrace(th)); + } + } + + activity().handleSearchResults(results); + } + + /** + * Called by {@link io.github.rosemoe.editor.widget.CodeEditor CodeEditor} to show location links in EditorActivity. + * These location links are mapped as {@link org.eclipse.lsp4j.Location Location} and then {@link #showLocations(List) } is called. + */ public void showLocationLinks(List locations) { - LOG.info("showLocationLinks", JSONUtility.prettyPrinter.toJson(locations)); + + if(locations == null || locations.size() <= 0) { + return; + } + + showLocations(locations + .stream() + .filter(l -> l != null) + .map(l -> asLocation(l)) + .filter(l -> l != null) + .collect(Collectors.toList()) + ); } /** @@ -138,6 +259,62 @@ public abstract class IDELanguageClient implements LanguageClient { public void telemetryEvent(Object p1) { LOG.info("telemetryEvent: ", gson.toJson(p1)); } + + private Location asLocation(LocationLink link) { + if(link == null || link.getTargetRange() == null || link.getTargetUri() == null) return null; + final Location location = new Location(); + location.setUri(link.getTargetUri()); + location.setRange(link.getTargetRange()); + return location; + } + + /** + * Formats (highlights) a method signature + * + * @param signature Signature information + * @param paramIndex Currently active parameter index + */ + private CharSequence formatSignature(SignatureInformation signature, int paramIndex) { + String name = signature.getLabel(); + name = name.substring(0, name.indexOf("(")); + + SpannableStringBuilder sb = new SpannableStringBuilder(); + sb.append(name, new ForegroundColorSpan(0xffffffff), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); + sb.append("(", new ForegroundColorSpan(0xff4fc3f7), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); + + List params = signature.getParameters(); + for(int i=0;i mapAsGroup(Map> diags) { + List groups = new ArrayList<>(); + if(diags == null || diags.size() <= 0) + return groups; + for(File file : diags.keySet()) { + List fileDiags = diags.get(file); + if(fileDiags == null || fileDiags.size() <= 0) + continue; + DiagnosticGroup group = new DiagnosticGroup(R.drawable.ic_language_java, file, fileDiags); + groups.add(group); + } + return groups; + } + + public DiagnosticsAdapter newDiagnosticsAdapter() { + return new DiagnosticsAdapter(mapAsGroup(this.diagnostics), activity()); + } /** * Reports connection progress diff --git a/app/src/main/java/com/itsaky/androidide/lsp/LSP.java b/app/src/main/java/com/itsaky/androidide/lsp/LSP.java index e93863299..cd135f5df 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/LSP.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/LSP.java @@ -1,7 +1,7 @@ package com.itsaky.androidide.lsp; -import com.google.gson.Gson; import com.itsaky.androidide.app.StudioApp; +import com.itsaky.androidide.interfaces.EditorActivityProvider; import com.itsaky.androidide.lsp.client.java.JavaLanguageClient; import com.itsaky.androidide.shell.ShellServer; import com.itsaky.androidide.utils.Environment; @@ -9,32 +9,34 @@ import com.itsaky.androidide.utils.Logger; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.ClientCapabilities; import org.eclipse.lsp4j.ClientInfo; +import org.eclipse.lsp4j.ColorProviderCapabilities; +import org.eclipse.lsp4j.CompletionCapabilities; +import org.eclipse.lsp4j.CreateFilesParams; +import org.eclipse.lsp4j.DeleteFilesParams; +import org.eclipse.lsp4j.DidChangeConfigurationCapabilities; +import org.eclipse.lsp4j.DidChangeWatchedFilesCapabilities; +import org.eclipse.lsp4j.DidChangeWatchedFilesParams; +import org.eclipse.lsp4j.ExecuteCommandCapabilities; +import org.eclipse.lsp4j.FileCreate; +import org.eclipse.lsp4j.FileDelete; +import org.eclipse.lsp4j.FileOperationsWorkspaceCapabilities; import org.eclipse.lsp4j.GeneralClientCapabilities; import org.eclipse.lsp4j.InitializeParams; import org.eclipse.lsp4j.InitializeResult; import org.eclipse.lsp4j.InitializedParams; +import org.eclipse.lsp4j.SynchronizationCapabilities; import org.eclipse.lsp4j.TextDocumentClientCapabilities; import org.eclipse.lsp4j.WindowClientCapabilities; import org.eclipse.lsp4j.WorkspaceClientCapabilities; import org.eclipse.lsp4j.WorkspaceFolder; import org.eclipse.lsp4j.services.LanguageServer; -import java.util.concurrent.ExecutionException; -import java.util.Optional; -import org.eclipse.lsp4j.CallHierarchyCapabilities; -import org.eclipse.lsp4j.CodeActionCapabilities; -import org.eclipse.lsp4j.DidChangeConfigurationCapabilities; -import org.eclipse.lsp4j.DidChangeWatchedFilesCapabilities; -import org.eclipse.lsp4j.ExecuteCommandCapabilities; -import org.eclipse.lsp4j.FileOperationsWorkspaceCapabilities; -import org.eclipse.lsp4j.SemanticTokensCapabilities; -import org.eclipse.lsp4j.SynchronizationCapabilities; -import org.eclipse.lsp4j.ColorProviderCapabilities; -import org.eclipse.lsp4j.CompletionCapabilities; -import org.eclipse.lsp4j.CompletionItemCapabilities; -import com.itsaky.androidide.interfaces.EditorActivityProvider; +import org.eclipse.lsp4j.RenameFilesParams; +import org.eclipse.lsp4j.FileRename; /** * A manager class to manage Language Server Protocol implementations @@ -108,6 +110,20 @@ public class LSP { } } + /** + * Send initialized notification to Language server + */ + public static void initialized() { + + final LanguageServer server = LSPProvider.getServerForLanguage(LSPProvider.LANGUAGE_JAVA); + if (server == null) + return; + + // Initialized params do not have any parameters + server.initialized(new InitializedParams()); + + } + /** * Sends a shutdown request to the java language server */ @@ -142,6 +158,83 @@ public class LSP { PROVIDER = provider; } + public static void notifyFileCreated(File file) { + if(!shouldSendFileActionNotification(file)) return; + + final CreateFilesParams params = + new CreateFilesParams( + List.of( + new FileCreate( + file.toURI().toString() + ) + ) + ); + + for(Map.Entry entry : LSPProvider.getAvailableServers().entrySet()) { + final LanguageServer server = entry.getValue(); + if(server == null) { + server.getWorkspaceService().didCreateFiles(params); + } + } + } + + public static void notifyFileDeleted(File file) { + if(!shouldSendFileActionNotification(file)) return; + + final DeleteFilesParams params = + new DeleteFilesParams( + List.of( + new FileDelete( + file.toURI().toString() + ) + ) + ); + + for(Map.Entry entry : LSPProvider.getAvailableServers().entrySet()) { + final LanguageServer server = entry.getValue(); + if(server == null) { + server.getWorkspaceService().didDeleteFiles(params); + } + } + } + + public static void notifyFileRenamed(File file, String newName) { + if(!shouldSendFileActionNotification(file)) return; + + final File newFile = new File(file.getParentFile(), newName); + final RenameFilesParams params = + new RenameFilesParams( + List.of( + new FileRename( + file.toURI().toString(), // Old uri + newFile.toURI().toString() // New uri + ) + ) + ); + + for(Map.Entry entry : LSPProvider.getAvailableServers().entrySet()) { + final LanguageServer server = entry.getValue(); + if(server == null) { + server.getWorkspaceService().didRenameFiles(params); + } + } + } + + public static void notifyWatchedFilesChanged(final DidChangeWatchedFilesParams params) { + for(Map.Entry entry : LSPProvider.getAvailableServers().entrySet()) { + final LanguageServer server = entry.getValue(); + if(server == null) { + server.getWorkspaceService().didChangeWatchedFiles(params); + } + } + } + + public static boolean shouldSendFileActionNotification(File file) { + // TODO Check if we should send notification to any language server + // which handles this type of files + return true; + } + /** * Shuts down all known language server */ diff --git a/app/src/main/java/com/itsaky/androidide/lsp/client/java/JavaLanguageClient.java b/app/src/main/java/com/itsaky/androidide/lsp/client/java/JavaLanguageClient.java index 12df45a0d..1fde02619 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/client/java/JavaLanguageClient.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/client/java/JavaLanguageClient.java @@ -66,10 +66,6 @@ public class JavaLanguageClient extends IDELanguageClient { LOG.info("notifyProgress: ", gson.toJson(p1)); } - @Override - public void publishDiagnostics(PublishDiagnosticsParams p1) { - } - @Override public CompletableFuture refreshCodeLenses() { return null; diff --git a/app/src/main/java/com/itsaky/androidide/models/CompletionEdit.java b/app/src/main/java/com/itsaky/androidide/models/CompletionEdit.java deleted file mode 100644 index 79c9ebbf3..000000000 --- a/app/src/main/java/com/itsaky/androidide/models/CompletionEdit.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.itsaky.androidide.models; - -public class CompletionEdit { - public String insertText; - public InsertPosition position; - - public CompletionEdit(String insertText, InsertPosition position) { - this.insertText = insertText; - this.position = position; - } - - public static class InsertPosition { - public int line; - public int column; - - public InsertPosition(int line) { - this(line, -1); - } - - public InsertPosition(int line, int column) { - this.line = line; - this.column = column; - } - } -} diff --git a/app/src/main/java/com/itsaky/androidide/models/CompletionItemWrapper.java b/app/src/main/java/com/itsaky/androidide/models/CompletionItemWrapper.java deleted file mode 100644 index 5093047b2..000000000 --- a/app/src/main/java/com/itsaky/androidide/models/CompletionItemWrapper.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.itsaky.androidide.models; - -import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.language.java.manager.JavaCharacter; -import com.itsaky.androidide.language.java.server.JavaLanguageServer; -import com.itsaky.lsp.CompletionItem; -import com.itsaky.lsp.CompletionItemKind; -import com.itsaky.lsp.Position; -import com.itsaky.lsp.Range; -import com.itsaky.lsp.TextDocumentIdentifier; -import com.itsaky.lsp.TextDocumentPositionParams; -import com.itsaky.lsp.TextEdit; -import io.github.rosemoe.editor.text.Content; -import io.github.rosemoe.editor.text.Cursor; -import io.github.rosemoe.editor.widget.CodeEditor; -import java.util.List; -import io.github.rosemoe.editor.text.CharPosition; -import com.itsaky.androidide.utils.Logger; - -public class CompletionItemWrapper implements SuggestItem, Comparable { - - private CompletionItem item; - private String prefix; - - public CompletionItemWrapper(CompletionItem item, String prefix) { - this.item = item; - this.prefix = prefix; - } - - public String getInsertText() { - return item.insertText == null ? item.label : item.insertText; - } - - @Override - public String getName() { - return item.label; - } - - @Override - public String getDescription() { - return item.detail; - } - - @Override - public String getReturnType() { - return CompletionItemKind.asString(item.kind); - } - - @Override - public char getTypeHeader() { - return getReturnType().charAt(0); - } - - @Override - public String getSortText() { - return item.kind + getName(); - } - - @Override - public void onSelectThis(CodeEditor editor) { - try { - final Cursor cursor = editor.getCursor(); - if(cursor.isSelected()) return; - Range range = getIdentifierRange(cursor.getLeft(), editor.getText()); - String text = getInsertText(); - final boolean shiftLeft = text.contains("$0"); - final boolean atEnd = text.endsWith("$0"); - text = text.replace("$0", ""); - - editor.getText().delete(range.start.line, range.start.column, range.end.line, range.end.column); - cursor.onCommitText(text); - - if(shiftLeft && !atEnd) { - editor.moveSelectionLeft(); - } - - if(item.command != null - && item.command.command != null - && item.command.command.equals(CompletionItem.COMMAND_TRIGGER_PARAMETER_HINTS)) { - requestSignature(editor); - } - - final List edits = item.additionalTextEdits; - if(edits != null && edits.size() > 0) { - for(int i=0;i 0 && JavaCharacter.isJavaIdentifierPart(content.charAt(start - 1))) { - start--; - } - - CharPosition startPos = content.getIndexer().getCharPosition(start); - CharPosition endPos = content.getIndexer().getCharPosition(end); - return new Range(new Position(startPos.line, startPos.column), new Position(endPos.line, endPos.column)); - } - - private void requestSignature(CodeEditor editor) { - final JavaLanguageServer server = StudioApp.getInstance().getJavaLanguageServer(); - if (server != null) { - TextDocumentPositionParams p = new TextDocumentPositionParams(); - p.textDocument = new TextDocumentIdentifier(editor.getFile().toURI()); - p.position = new Position(editor.getCursor().getLeftLine(), editor.getCursor().getLeftColumn()); - server.signatureHelp(p, editor.getFile()); - } - } - - @Override - public int compareTo(Object p1) { - if(p1 instanceof CompletionItemWrapper) { - - CompletionItemWrapper that = (CompletionItemWrapper) p1; - return this.getSortText().compareTo(that.getSortText()); - } - return 1; - } - - public CompletionItem getItem() { - return item; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/models/CompletionListItem.java b/app/src/main/java/com/itsaky/androidide/models/CompletionListItem.java deleted file mode 100644 index db0d876b8..000000000 --- a/app/src/main/java/com/itsaky/androidide/models/CompletionListItem.java +++ /dev/null @@ -1,214 +0,0 @@ -package com.itsaky.androidide.models; - -import android.graphics.drawable.Drawable; -import io.github.rosemoe.editor.struct.CompletionItem; -import java.util.ArrayList; -import java.util.List; - -public class CompletionListItem extends CompletionItem { - private String detail; - private String itemType; - private Type type; - - private List additionalEdits; - - public CompletionListItem() { - super("", ""); - } - - public CompletionListItem setLabel(String label) { - this.label = label; - return this; - } - - public CompletionListItem setCommit(String commit) { - this.commit = commit; - cursorOffset(commit.length()); - return this; - } - - public CompletionListItem setDesc(String desc) { - this.desc = desc; - return this; - } - - public CompletionListItem setIcon(Drawable icon) { - this.icon = icon; - return this; - } - - public String getLabel() { - return this.label; - } - - public String getCommit() { - return this.commit; - } - - public String getDesc() { - return this.desc; - } - - public Drawable getIcon() { - return this.icon; - } - - public CompletionListItem setType(Type type) { - this.type = type; - return this; - } - - public Type getType() { - return type; - } - - public CompletionListItem setItemType(String type) { - this.itemType = type; - return this; - } - - public String getItemType() { - return itemType; - } - - public CompletionListItem setDetail(String detail) { - this.detail = detail; - return this; - } - - public String getDetail() { - return detail; - } - - public CompletionListItem setAdditionalEdits(List edits) { - this.additionalEdits = edits; - return this; - } - - public List getAdditionalEdits() { - if (this.additionalEdits == null) - this.additionalEdits = new ArrayList<>(); - - return additionalEdits; - } - - public CompletionListItem addAdditionalEdit(CompletionEdit edit) { - if (edit != null) { - getAdditionalEdits().add(edit); - } - return this; - } - - public boolean hasAdditionalEdits() { - return getAdditionalEdits() != null && getAdditionalEdits().size() > 0; - } - - public String getSortText() { - if (getType() == Type.LOCAL_VARIABLE) - return "0" + getLabel(); - - if (getType() == Type.FIELD) - return "1" + getLabel(); - - if (getType() == Type.KEYWORD) - return "2" + getLabel(); - - if (getType() == Type.METHOD) - return "3" + getLabel(); - - if (getType() == Type.ENUM) - return "4" + getLabel(); - - if (getType() == Type.INTERFACE) - return "5" + getLabel(); - - if (getType() == Type.CLASS) - return "6" + getLabel(); - - if (getType() == Type.NOT_IMPORTED_CLASS) - return "7" + getLabel(); - - if (getType() == Type.ATTRIBUTE) - return "8" + getLabel(); - - if (getType() == Type.WIDGET) - return "9" + getLabel(); - - if (getType() == Type.OBJECT) - return "10" + getLabel(); - return getLabel(); - } - - public static enum Type { - ATTRIBUTE('A'), - CLASS('C'), - ENUM('E'), - FIELD('F'), - INTERFACE('I'), - KEYWORD('K'), - LOCAL_VARIABLE('V'), - METHOD('M'), - NOT_IMPORTED_CLASS(' '), - OBJECT('O'), - WIDGET('W'); - - private char c; - private Type(char c) { - this.c = c; - } - - public String getAsString() { - return String.valueOf(c); - } - - public char get() { - return c; - } - } - - public int compareTo(CompletionListItem obj) { - return getSortText().compareTo(obj.getSortText()); - } - - public CompletionListItem clone() { - CompletionListItem item = new CompletionListItem(); - item.setCommit(getCommit()); - item.setDesc(getDesc()); - item.setDetail(getDetail()); - item.setIcon(getIcon()); - item.setItemType(getItemType()); - item.setLabel(getLabel()); - item.setType(getType()); - return item; - } - - @Override - public boolean equals(Object obj) { - if(obj != null && obj instanceof CompletionListItem) { - CompletionListItem that = (CompletionListItem) obj; - return this.getLabel().equals(that.getLabel()) - && this.getDesc().equals(that.getDesc()) - && this.getDetail().equals(that.getDetail()) - && this.getCommit().equals(that.getCommit()) - && this.getItemType() == that.getItemType() - && this.hasAdditionalEdits() == that.hasAdditionalEdits() - && this.getAdditionalEdits().size() == that.getAdditionalEdits().size() - && this.getAdditionalEdits() == that.getAdditionalEdits(); - } - return false; - } - - @Override - public String toString() { - return - "[" - + "\ncommit = " + getCommit() - + "\ndesc = " + getDesc() - + "\ndetail = " + getDetail() - + "\nicon = " + getIcon() - + "\nitemType = " + getItemType() - + "\nlabel = " + getLabel() - + "\ntype = " + getType() - + "\n]"; - } -} diff --git a/app/src/main/java/com/itsaky/androidide/models/DiagnosticGroup.java b/app/src/main/java/com/itsaky/androidide/models/DiagnosticGroup.java index f1f93b14e..2ca32c63a 100644 --- a/app/src/main/java/com/itsaky/androidide/models/DiagnosticGroup.java +++ b/app/src/main/java/com/itsaky/androidide/models/DiagnosticGroup.java @@ -1,8 +1,8 @@ package com.itsaky.androidide.models; -import com.itsaky.lsp.Diagnostic; import java.io.File; import java.util.List; +import org.eclipse.lsp4j.Diagnostic; public class DiagnosticGroup { public int icon; diff --git a/app/src/main/java/com/itsaky/androidide/models/GradleSuggestItem.java b/app/src/main/java/com/itsaky/androidide/models/GradleSuggestItem.java deleted file mode 100644 index f33c9087a..000000000 --- a/app/src/main/java/com/itsaky/androidide/models/GradleSuggestItem.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.itsaky.androidide.models; - -import io.github.rosemoe.editor.text.CharPosition; -import io.github.rosemoe.editor.text.Content; -import io.github.rosemoe.editor.widget.CodeEditor; - -public class GradleSuggestItem implements SuggestItem { - - private String label; - private String desc; - private String prefix; - private boolean isArtifact; - - public GradleSuggestItem(String label, String desc, String prefix, boolean isArtifact) { - this.label = label; - this.desc = desc; - this.prefix = prefix; - this.isArtifact = isArtifact; - } - - @Override - public String getName() { - return label; - } - - @Override - public String getDescription() { - return desc; - } - - @Override - public String getReturnType() { - return ""; - } - - @Override - public char getTypeHeader() { - return ' '; - } - - @Override - public String getSortText() { - return label; - } - - @Override - public void onSelectThis(CodeEditor editor) { - try { - final int length = prefix.length(); - final int start = editor.getCursor().getLeft() - length; - final int end = editor.getCursor().getLeft(); - final CharPosition s = editor.getText().getIndexer().getCharPosition(start); - Content editable = editor.getText(); - editable.delete(start, end); - editable.insert(s.line, s.column, getName()); - } catch (Throwable ignored) {} - } -} diff --git a/app/src/main/java/com/itsaky/androidide/services/IDEService.java b/app/src/main/java/com/itsaky/androidide/services/IDEService.java index f7afa397d..2d4c6e1f8 100644 --- a/app/src/main/java/com/itsaky/androidide/services/IDEService.java +++ b/app/src/main/java/com/itsaky/androidide/services/IDEService.java @@ -7,9 +7,8 @@ import com.blankj.utilcode.util.FileUtils; import com.google.gson.Gson; import com.itsaky.androidide.R; import com.itsaky.androidide.app.StudioApp; -import com.itsaky.androidide.language.java.server.JavaLanguageServer; +import com.itsaky.androidide.lsp.LSP; import com.itsaky.androidide.managers.PreferenceManager; -import com.itsaky.androidide.models.AndroidProject; import com.itsaky.androidide.models.project.IDEModule; import com.itsaky.androidide.models.project.IDEProject; import com.itsaky.androidide.shell.ShellServer; @@ -19,9 +18,6 @@ import com.itsaky.androidide.tasks.gradle.build.AssembleDebug; import com.itsaky.androidide.tasks.gradle.resources.UpdateResourceClassesTask; import com.itsaky.androidide.utils.Environment; import com.itsaky.androidide.utils.Logger; -import com.itsaky.lsp.DidChangeWatchedFilesParams; -import com.itsaky.lsp.FileChangeType; -import com.itsaky.lsp.FileEvent; import com.itsaky.toaster.Toaster; import java.io.File; import java.io.FileFilter; @@ -33,6 +29,9 @@ import java.util.Date; import java.util.List; import java.util.Locale; import java.util.Optional; +import org.eclipse.lsp4j.DidChangeWatchedFilesParams; +import org.eclipse.lsp4j.FileChangeType; +import org.eclipse.lsp4j.FileEvent; public class IDEService implements ShellServer.Callback { @@ -201,11 +200,7 @@ public class IDEService implements ShellServer.Callback { * get completions from updated classpaths */ private void notifyExternalSourceChange() { - JavaLanguageServer server = app.getJavaLanguageServer(); - if(mIDEProject == null || server == null) return; - - server.didChangeWatchedFiles(new DidChangeWatchedFilesParams(createSourceChangeEvents())); - server.buildModified(); + LSP.notifyWatchedFilesChanged(new DidChangeWatchedFilesParams(createSourceChangeEvents())); if(listener != null) { listener.onBuildModified(); @@ -232,7 +227,7 @@ public class IDEService implements ShellServer.Callback { final List sources = FileUtils.listFilesInDirWithFilter(generated, JAVA_FILTER, true); if(sources == null) continue; for(File source : sources) { - events.add(new FileEvent(source.toURI(), FileChangeType.Changed)); + events.add(new FileEvent(source.toURI().toString(), FileChangeType.Changed)); } } return events; diff --git a/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/java/JavaLexerImpl.java b/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/java/JavaLexerImpl.java index 047a1ce46..ae0fe92e8 100644 --- a/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/java/JavaLexerImpl.java +++ b/app/src/main/java/com/itsaky/androidide/syntax/lexer/impls/java/JavaLexerImpl.java @@ -5,24 +5,17 @@ import com.itsaky.androidide.syntax.lexer.Lexer; import com.itsaky.androidide.syntax.lexer.impls.BaseJavaLexer; import com.itsaky.androidide.syntax.lexer.tokens.Token; import com.itsaky.androidide.syntax.lexer.tokens.TokenType; -import com.itsaky.lsp.JavaColors; -import com.itsaky.lsp.Range; import io.github.rosemoe.editor.struct.BlockLine; import io.github.rosemoe.editor.text.TextAnalyzeResult; import io.github.rosemoe.editor.widget.EditorColorScheme; import java.io.IOException; import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; import org.antlr.v4.runtime.CharStreams; -import java.util.Map; -import java.util.HashMap; -import com.itsaky.lsp.Position; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; public class JavaLexerImpl extends BaseJavaLexer implements Lexer { - private JavaColors javaColors; - public JavaLexerImpl(String content, TextAnalyzeResult colors) { this.content = content; this.colors = colors; @@ -33,10 +26,6 @@ public class JavaLexerImpl extends BaseJavaLexer implements Lexer { this.isFirst = true; } - public void setJavaColors(JavaColors colors) { - this.javaColors = colors; - } - @Override public void init() throws IOException { lexer = new JavaLexer(CharStreams.fromReader(new StringReader(content))); @@ -227,92 +216,6 @@ public class JavaLexerImpl extends BaseJavaLexer implements Lexer { break; case JavaLexer.IDENTIFIER : type = TokenType.IDENTIFIER; - - if(isPackageName(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.PACKAGE_NAME); - break; - } - - if(isEnumType(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.ENUM_TYPE); - break; - } - - if(isClassName(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.TYPE_NAME); - break; - } - - if(isAnnotationType(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.ANNOTATION); - break; - } - - if(isInterface(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.INTERFACE); - break; - } - - if(isEnum(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.ENUM); - break; - } - - if(isStaticField(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.STATIC_FIELD); - break; - } - - if(isField(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.FIELD); - break; - } - - if(isParameter(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.PARAMETER); - break; - } - - if(isLocal(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.LOCAL_VARIABLE); - break; - } - - if(isExceptionParam(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.EXCEPTION_PARAM); - break; - } - - if(isMethod(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.METHOD); - break; - } - - if(isConstructor(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.CONSTRUCTOR); - break; - } - - if(isStaticInit(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.STATIC_INIT); - break; - } - - if(isInstanceInit(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.INSTANCE_INIT); - break; - } - - if(isTypeParam(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.TYPE_PARAM); - break; - } - - if(isResourceVariable(line, column)) { - colors.addIfNeeded(line, column, EditorColorScheme.RESOURCE_VARIABLE); - break; - } - colors.addIfNeeded(line, column, EditorColorScheme.TEXT_NORMAL); break; case JavaLexer.LBRACE : @@ -360,101 +263,4 @@ public class JavaLexerImpl extends BaseJavaLexer implements Lexer { return type; } - - private boolean isEnumType(int line, int column) { - if(javaColors == null || javaColors.enumTypes == null) return false; - return isInRange(javaColors.enumTypes, line, column); - } - - private boolean isAnnotationType(int line, int column) { - if(javaColors == null || javaColors.annotationTypes == null) return false; - return isInRange(javaColors.annotationTypes, line, column); - } - - private boolean isInterface(int line, int column) { - if(javaColors == null || javaColors.interfaces == null) return false; - return isInRange(javaColors.interfaces, line, column); - } - - private boolean isEnum(int line, int column) { - if(javaColors == null || javaColors.enums == null) return false; - return isInRange(javaColors.enums, line, column); - } - - private boolean isParameter(int line, int column) { - if(javaColors == null || javaColors.parameters == null) return false; - return isInRange(javaColors.parameters, line, column); - } - - private boolean isExceptionParam(int line, int column) { - if(javaColors == null || javaColors.exceptionParams == null) return false; - return isInRange(javaColors.exceptionParams, line, column); - } - - private boolean isConstructor(int line, int column) { - if(javaColors == null || javaColors.constructors == null) return false; - return isInRange(javaColors.constructors, line, column); - } - - private boolean isStaticInit(int line, int column) { - if(javaColors == null || javaColors.staticInits == null) return false; - return isInRange(javaColors.staticInits, line, column); - } - - private boolean isInstanceInit(int line, int column) { - if(javaColors == null || javaColors.instanceInits == null) return false; - return isInRange(javaColors.instanceInits, line, column); - } - - private boolean isTypeParam(int line, int column) { - if(javaColors == null || javaColors.typeParams == null) return false; - return isInRange(javaColors.typeParams, line, column); - } - - private boolean isResourceVariable(int line, int column) { - if(javaColors == null || javaColors.resourceVariables == null) return false; - return isInRange(javaColors.resourceVariables, line, column); - } - - private boolean isPackageName(int line, int column) { - if(javaColors == null || javaColors.packages == null) return false; - return isInRange(javaColors.packages, line, column); - } - - private boolean isClassName(int line, int column) { - if(javaColors == null || javaColors.classNames == null) return false; - return isInRange(javaColors.classNames, line, column); - } - - private boolean isField(int line, int column) { - if(javaColors == null || javaColors.fields == null) return false; - return isInRange(javaColors.fields, line, column); - } - - private boolean isStaticField(int line, int column) { - if(javaColors == null || javaColors.statics == null) return false; - return isInRange(javaColors.statics, line, column); - } - - private boolean isMethod(int line, int column) { - if(javaColors == null || javaColors.methods == null) return false; - return isInRange(javaColors.methods, line, column); - } - - private boolean isLocal(int line, int column) { - if(javaColors == null || javaColors.locals == null) return false; - return isInRange(javaColors.locals, line, column); - } - - private boolean isInRange(List ranges, int line, int column) { - if(ranges != null && ranges.size() > 0) { - for(int i=0;i mSignatureHelpTriggerChars = new ArrayList<>(); + private Map mLineColors; private Map mDiagnostics; private Map> stringMap; @@ -617,10 +622,10 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca final Set keys = mDiagnostics.keySet(); Range found = null; for(Range r : keys) { - if(r.start.line <= range.getStart().getLine() - && r.start.column <= range.getStart().getCharacter() - && r.end.line >= range.getEnd().getLine() - && r.end.column >= range.getEnd().getCharacter()) { + if(r.getStart().getLine() <= range.getStart().getLine() + && r.getStart().getCharacter() <= range.getStart().getCharacter() + && r.getEnd().getLine() >= range.getEnd().getLine() + && r.getEnd().getCharacter() >= range.getEnd().getCharacter()) { found = r; break; } @@ -641,7 +646,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca for(Range r : keys) { if(r == null) continue; - if(r.start.line <= line && line <= r.end.line) + if(r.getStart().getLine() <= line && line <= r.getEnd().getLine()) diags.add(mDiagnostics.get(r)); } @@ -681,9 +686,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca public CodeEditor putLineColor(HexColor index, int color) { createMapIfNull(); - if(this.mLineColors != null) { - mLineColors.put(index, color); - } + mLineColors.put(index, color); return this; } @@ -873,27 +876,47 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca } Either codeActionOptions = c.getCodeActionProvider(); - if(codeActionOptions.isLeft()) { - mCodeActionsEnabled = codeActionOptions.getLeft(); + if(codeActionOptions == null) { + setCodeActionsEnabled(false); } else { - CodeActionOptions options = codeActionOptions.getRight(); - mCodeActionsEnabled = options != null; + if(codeActionOptions.isLeft()) { + setCodeActionsEnabled(codeActionOptions.getLeft()); + } else { + CodeActionOptions options = codeActionOptions.getRight(); + setCodeActionsEnabled(options != null); + } } Either definitionOptions = c.getDefinitionProvider(); - if(definitionOptions.isLeft()) { - mGotoDefinitionEnabled = definitionOptions.getLeft(); + if(definitionOptions == null) { + setGotoDefinitionEnabled(false); } else { - DefinitionOptions options = definitionOptions.getRight(); - mGotoDefinitionEnabled = options != null; + if(definitionOptions.isLeft()) { + setGotoDefinitionEnabled(definitionOptions.getLeft()); + } else { + DefinitionOptions options = definitionOptions.getRight(); + setGotoDefinitionEnabled(options != null); + } } Either referenceOptions = c.getReferencesProvider(); - if(definitionOptions.isLeft()) { - mFindReferencesEnabled = referenceOptions.getLeft(); + if(referenceOptions == null) { + setFindReferencesEnabled(false); } else { - ReferenceOptions options = referenceOptions.getRight(); - mFindReferencesEnabled = options != null; + if(definitionOptions.isLeft()) { + setFindReferencesEnabled(referenceOptions.getLeft()); + } else { + ReferenceOptions options = referenceOptions.getRight(); + setFindReferencesEnabled(options != null); + } + } + + SignatureHelpOptions signatureOptions = c.getSignatureHelpProvider(); + if(signatureOptions == null) { + setSignatureHelpEnabled(false); + } else { + setSignatureHelpEnabled(true); + mSignatureHelpTriggerChars = new ArrayList(signatureOptions.getTriggerCharacters()); } } @@ -1485,10 +1508,10 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca for(int i=0;i d.range.start.line) startCol = 0; - if(line > d.range.end.line) endCol = 0; + int startCol = d.getRange().getStart().getCharacter(); + int endCol = d.getRange().getEnd().getCharacter(); + if(line > d.getRange().getStart().getCharacter()) startCol = 0; + if(line > d.getRange().getEnd().getCharacter()) endCol = 0; final int paintStart = Math.max(firstVisibleChar, startCol); final int paintEnd = Math.min(lastVisibleChar, endCol); final float width = measureText(mBuffer, paintStart, paintEnd - paintStart); @@ -1497,7 +1520,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca r.top = r.bottom - getRowHeight() * 0.2f; r.left = paintingOffset + measureText(mBuffer, firstVisibleChar, paintStart - firstVisibleChar); r.right = r.left + width; - mPaint.setColor(diagnosticColor(d.severity)); + mPaint.setColor(diagnosticColor(d.getSeverity())); drawZigzagUnderline(r, canvas, mPaint); } } @@ -1610,12 +1633,12 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca } } - private int diagnosticColor(int severity) { + private int diagnosticColor(DiagnosticSeverity severity) { int id = EditorColorScheme.DIAGNOSTIC_HINT; switch(severity) { - case DiagnosticSeverity.Error : id = EditorColorScheme.DIAGNOSTIC_ERROR; break; - case DiagnosticSeverity.Warning : id = EditorColorScheme.DIAGNOSTIC_WARNING; break; - case DiagnosticSeverity.Information : id = EditorColorScheme.DIAGNOSTIC_INFO; break; + case Error : id = EditorColorScheme.DIAGNOSTIC_ERROR; break; + case Warning : id = EditorColorScheme.DIAGNOSTIC_WARNING; break; + case Information : id = EditorColorScheme.DIAGNOSTIC_INFO; break; default : id = EditorColorScheme.DIAGNOSTIC_ERROR; break; } return mColors.getColor(id); @@ -2706,6 +2729,10 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca public void setFindReferencesEnabled(boolean findReferencesEnabled) { mFindReferencesEnabled = findReferencesEnabled; } + + public void setSignatureHelpEnabled(boolean enabled) { + this.mSignatureHelpEnabled = enabled; + } /** * @see CodeEditor#setAutoCompletionEnabled(boolean) @@ -2725,6 +2752,10 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca public boolean isFindReferencesEnabled() { return mFindReferencesEnabled && mLanguageServer != null; } + + public boolean isSignatureHelpEnabled() { + return mSignatureHelpEnabled && mLanguageServer != null; + } /** * Sets non-printable painting flags. @@ -4571,12 +4602,6 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca } } - private JLSRequestor jlsRequestor; - - public void setJLSRequestor(JLSRequestor requestor) { - this.jlsRequestor = requestor; - } - public void commentLine() { if(getFile() == null) return; @@ -4642,7 +4667,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca try { final DefinitionParams params = new DefinitionParams(); - params.setTextDocument(new TextDocumentIdentifier(getFile().toURI().toString())); + params.setTextDocument(getDocumentIdentifier()); params.setPosition(getCursorAsLSPPosition()); final CompletableFuture, List>> future = mLanguageServer.getTextDocumentService().definition(params); future.whenComplete((e, t) -> { @@ -4650,39 +4675,43 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca final Throwable th = t; final IDELanguageClient client = LSPProvider.getClientForLanguage(mLanguage.getLanguageCode()); - if(client == null || future.isCancelled() || future.isCompletedExceptionally()) { + if(either == null || client == null || future.isCancelled() || future.isCompletedExceptionally()) { showDefinitionNotFound(pd); return; } if(either.isLeft()) { - List locations = either.getLeft(); + final List locations = either.getLeft(); if(locations == null || locations.size() <= 0) { showDefinitionNotFound(pd); return; } - if(locations.size() == 1) { - Location location = locations.get(0); - showDocument(client, location.getUri(), location.getRange()); - } else { - client.showLocations(locations); - } + ThreadUtils.runOnUiThread(() -> { + if(locations.size() == 1) { + Location location = locations.get(0); + showDocument(client, location.getUri(), location.getRange()); + } else { + client.showLocations(locations); + } + }); dismissOnUiThread(pd); } else if(either.isRight()) { - List locations = either.getRight(); + final List locations = either.getRight(); if(locations == null || locations.size() <= 0) { showDefinitionNotFound(pd); return; } - if(locations.size() == 1) { - LocationLink location = locations.get(0); - showDocument(client, location.getTargetUri(), location.getTargetSelectionRange()); - } else { - client.showLocationLinks(locations); - } + ThreadUtils.runOnUiThread(() -> { + if(locations.size() == 1) { + LocationLink location = locations.get(0); + showDocument(client, location.getTargetUri(), location.getTargetSelectionRange()); + } else { + client.showLocationLinks(locations); + } + }); dismissOnUiThread(pd); } @@ -4699,19 +4728,41 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca }); } - private void dismissOnUiThread(final Dialog dialog) { - ThreadUtils.runOnUiThread(() -> { - dialog.dismiss(); - }); - } - public void findReferences() { - if(!isFindReferencesEnabled()) return; + if(!isFindReferencesEnabled() || getFile() == null) return; - final ProgressDialog pd = ProgressDialog.show(getContext(), null, getContext().getString(R.string.msg_finding_definition)); + final ProgressDialog pd = ProgressDialog.show(getContext(), null, getContext().getString(R.string.msg_finding_references)); try { + ReferenceParams params = new ReferenceParams(); + params.setTextDocument(getDocumentIdentifier()); + params.setPosition(getCursorAsLSPPosition()); + params.setContext(new ReferenceContext(true)); + final CompletableFuture> future = mLanguageServer.getTextDocumentService().references(params); + + future.whenComplete((l, t) -> { + final List locations = l; + final Throwable th = t; + + final IDELanguageClient client = LSPProvider.getClientForLanguage(mLanguage.getLanguageCode()); + + if(locations == null || client == null || future.isCancelled() || future.isCompletedExceptionally()) { + showReferencesNotFound(pd); + return; + } + + if(locations.isEmpty()) { + showReferencesNotFound(pd); + return; + } else { + ThreadUtils.runOnUiThread(() -> { + client.showLocations(locations); + }); + } + + dismissOnUiThread(pd); + }); } catch (Throwable th) { showReferencesNotFound(pd); } @@ -4724,18 +4775,56 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca }); } + public void signatureHelp(String insertedContent) { + if(mSignatureHelpEnabled + && mLanguageServer != null + && getFile() != null + && mSignatureHelpTriggerChars != null + && mSignatureHelpTriggerChars.size() > 0 + && mSignatureHelpTriggerChars.contains(insertedContent)) { + + SignatureHelpContext context = new SignatureHelpContext(); + context.setTriggerCharacter(insertedContent); + context.setTriggerKind(SignatureHelpTriggerKind.ContentChange); + + SignatureHelpParams params = new SignatureHelpParams(); + params.setPosition(getCursorAsLSPPosition()); + params.setTextDocument(getDocumentIdentifier()); + params.setContext(context); + + CompletableFuture future = mLanguageServer.getTextDocumentService().signatureHelp(params); + + future.whenComplete((h, t) -> { + final SignatureHelp help = h; + final Throwable th = t; + final IDELanguageClient client = LSPProvider.getClientForLanguage(mLanguage.getLanguageCode()); + + if(help == null || client == null || future.isCancelled() || future.isCompletedExceptionally()) { + return; + } + + ThreadUtils.runOnUiThread(() -> { + client.showSignatureHelp(help, getFile()); + }); + }); + } + } + + private void dismissOnUiThread(final Dialog dialog) { + ThreadUtils.runOnUiThread(() -> { + dialog.dismiss(); + }); + } + /** * Request the client to show the specific document in an editor and select the provided range */ private void showDocument(IDELanguageClient client, String uri, org.eclipse.lsp4j.Range range) { - LOG.info("showDocument called", "client = " + client, "uri" + uri, "range" + range); ShowDocumentParams params = new ShowDocumentParams(); params.setExternal(false); params.setSelection(range); params.setUri(uri); - LOG.info("ShowDocumentParams", JSONUtility.prettyPrinter.toJson(params)); client.showDocument(params); - LOG.info("sent showDocumentRequest"); } public void didSave () { @@ -4758,6 +4847,10 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca return new Position(getCursor().getLeftLine(), getCursor().getLeftColumn()); } + public TextDocumentIdentifier getDocumentIdentifier() { + return new TextDocumentIdentifier(getFile().toURI().toString()); + } + private boolean isInString() { final int line = getCursor().getLeftLine(); final int column = getCursor().getLeftColumn(); @@ -4766,7 +4859,7 @@ public class CodeEditor extends View implements ContentListener, TextAnalyzer.Ca if(strings == null || strings.isEmpty()) return false; for(int i=0;i diff --git a/lsp/src/main/java/com/itsaky/lsp/CancelParams.java b/lsp/src/main/java/com/itsaky/lsp/CancelParams.java deleted file mode 100644 index f735b0ed2..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CancelParams.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class CancelParams { - @SerializedName("id") - public int id; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CodeAction.java b/lsp/src/main/java/com/itsaky/lsp/CodeAction.java deleted file mode 100644 index bd0ae34eb..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CodeAction.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.GsonBuilder; -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class CodeAction { - @SerializedName("title") - public String title; - - @SerializedName("kind") - public String kind; - - @SerializedName("diagnostics") - public List diagnostics; - - @SerializedName("edit") - public WorkspaceEdit edit; - - @SerializedName("command") - public Command command; - - public static CodeAction NONE; - - @Override - public String toString() { - return new GsonBuilder().setPrettyPrinting().create().toJson(this); - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof CodeAction) { - CodeAction that = (CodeAction) obj; - return this.title.equals(that.title) - && this.kind.equals(that.kind); - } - return false; - } - - @Override - public int hashCode() { - return title.hashCode(); - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CodeActionContext.java b/lsp/src/main/java/com/itsaky/lsp/CodeActionContext.java deleted file mode 100644 index e9ae87ccc..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CodeActionContext.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.ArrayList; -import java.util.List; - -public class CodeActionContext { - @SerializedName("diagnostics") - public List diagnostics = new ArrayList<>(); - - @SerializedName("only") - public List only; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CodeActionKind.java b/lsp/src/main/java/com/itsaky/lsp/CodeActionKind.java deleted file mode 100644 index 328390172..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CodeActionKind.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.itsaky.lsp; - -public class CodeActionKind { - public static final String QuickFix = "quickfix", - Refactor = "refactor", - RefactorExtract = "refactor.extract", - RefactorInline = "refactor.inline", - RefactorRewrite = "refactor.rewrite", - Source = "source", - SourceOrganizeImports = "source.organizeImports"; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CodeActionParams.java b/lsp/src/main/java/com/itsaky/lsp/CodeActionParams.java deleted file mode 100644 index 475964f39..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CodeActionParams.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class CodeActionParams { - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; - - @SerializedName("range") - public Range range; - - @SerializedName("context") - public CodeActionContext context = new CodeActionContext(); -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CodeLens.java b/lsp/src/main/java/com/itsaky/lsp/CodeLens.java deleted file mode 100644 index 20cf6dc09..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CodeLens.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonElement; -import com.google.gson.annotations.SerializedName; - -public class CodeLens { - @SerializedName("range") - public Range range; - - @SerializedName("command") - public Command command; - - @SerializedName("data") - public JsonElement data; - - public CodeLens() {} - - public CodeLens(Range range, Command command, JsonElement data) { - this.range = range; - this.command = command; - this.data = data; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CodeLensParams.java b/lsp/src/main/java/com/itsaky/lsp/CodeLensParams.java deleted file mode 100644 index 3bab230d4..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CodeLensParams.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.itsaky.lsp; -import com.google.gson.annotations.SerializedName; - -public class CodeLensParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; - - public CodeLensParams() {} - - public CodeLensParams(TextDocumentIdentifier textDocument) { - this.textDocument = textDocument; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/Command.java b/lsp/src/main/java/com/itsaky/lsp/Command.java deleted file mode 100644 index 3f5c7604a..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/Command.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonArray; -import com.google.gson.annotations.SerializedName; - -public class Command { - - @SerializedName("title") - public String title; - - @SerializedName("command") - public String command; - - @SerializedName("arguments") - public JsonArray arguments; - - public Command() {} - - public Command(String title, String command, JsonArray arguments) { - this.title = title; - this.command = command; - this.arguments = arguments; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CompletionItem.java b/lsp/src/main/java/com/itsaky/lsp/CompletionItem.java deleted file mode 100644 index c96dda6bf..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CompletionItem.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonElement; -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class CompletionItem { - @SerializedName("label") - public String label; - - @SerializedName("kind") - public int kind; - - @SerializedName("detail") - public String detail; - - @SerializedName("documentation") - public MarkupContent documentation; - - @SerializedName("deprecated") - public Boolean deprecated; - - @SerializedName("preselect") - public Boolean preselect; - - @SerializedName("sortText") - public String sortText; - - @SerializedName("filterText") - public String filterText; - - @SerializedName("insertText") - public String insertText; - - @SerializedName("insertTextFormat") - public Integer insertTextFormat; - - @SerializedName("textEdit") - public TextEdit textEdit; - - @SerializedName("additionalTextEdits") - public List additionalTextEdits; - - @SerializedName("commitCharacters") - public List commitCharacters; - - @SerializedName("command") - public Command command; - - @SerializedName("data") - public JsonElement data; - - public static final String COMMAND_TRIGGER_PARAMETER_HINTS = "editor.action.triggerParameterHints"; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CompletionItemKind.java b/lsp/src/main/java/com/itsaky/lsp/CompletionItemKind.java deleted file mode 100644 index 11967001a..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CompletionItemKind.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.itsaky.lsp; - -public class CompletionItemKind { - public static final int Text = 1, - Method = 2, - Function = 3, - Constructor = 4, - Field = 5, - Variable = 6, - Class = 7, - Interface = 8, - Module = 9, - Property = 10, - Unit = 11, - Value = 12, - Enum = 13, - Keyword = 14, - Snippet = 15, - Color = 16, - File = 17, - Reference = 18, - Folder = 19, - EnumMember = 20, - Constant = 21, - Struct = 22, - Event = 23, - Operator = 24, - TypeParameter = 25; - - public static String asString(int kind) { - switch(kind) { - case Text : return "Text"; - case Method : return "Method"; - case Function : return "Function"; - case Constructor : return "Constructo"; - case Field: return "Field"; - case Variable : return "Variable"; - case Class : return "Class"; - case Interface : return "Interface"; - case Module : return "Module"; - case Property : return "Property"; - case Unit : return "Unit"; - case Value : return "Value"; - case Enum : return "Enum"; - case Keyword : return "Keyword"; - case Snippet : return "Snippet"; - case Color : return "Color"; - case File : return "File"; - case Reference : return "Reference"; - case Folder : return "Folder"; - case EnumMember : return "Enum Member"; - case Constant : return "Constant"; - case Struct : return "Struct"; - case Event : return "Event"; - case Operator : return "Operator"; - case TypeParameter : return "Type Parameter"; - default: return "Unknown"; - } - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CompletionList.java b/lsp/src/main/java/com/itsaky/lsp/CompletionList.java deleted file mode 100644 index a2fbc6fcf..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CompletionList.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.GsonBuilder; -import com.google.gson.annotations.SerializedName; -import java.util.ArrayList; -import java.util.List; - -public class CompletionList { - - @SerializedName("isIncomplete") - public boolean isIncomplete; - - @SerializedName("items") - public List items; - - public CompletionList() { - this.items = new ArrayList<>(); - } - - public CompletionList(boolean isIncomplete, List items) { - this.isIncomplete = isIncomplete; - this.items = items; - } - - @Override - public String toString() { - return new GsonBuilder().setPrettyPrinting().create().toJson(this, CompletionList.class); - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/CompletionTriggerKind.java b/lsp/src/main/java/com/itsaky/lsp/CompletionTriggerKind.java deleted file mode 100644 index dda106a87..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/CompletionTriggerKind.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.itsaky.lsp; - -public class CompletionTriggerKind { - /** - * Completion was triggered by typing an identifier (24x7 code complete), manual invocation (e.g Ctrl+Space) or via - * API. - */ - public static final int Invoked = 1; - - /** - * Completion was triggered by a trigger character specified by the `triggerCharacters` properties of the - * `CompletionRegistrationOptions`. - */ - public static final int TriggerCharacter = 2; - - /** Completion was re-triggered as the current completion list is incomplete. */ - public static final int TriggerForIncompleteCompletions = 3; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/Diagnostic.java b/lsp/src/main/java/com/itsaky/lsp/Diagnostic.java deleted file mode 100644 index 115807f4b..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/Diagnostic.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.ArrayList; -import java.util.List; - -public class Diagnostic { - @SerializedName("range") - public Range range; - - @SerializedName("severity") - public Integer severity; - - @SerializedName("code") - public String code; - - @SerializedName("source") - public String source; - - @SerializedName("message") - public String message; - - @SerializedName("tags") - public List tags; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DiagnosticSeverity.java b/lsp/src/main/java/com/itsaky/lsp/DiagnosticSeverity.java deleted file mode 100644 index ecb1b2f98..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DiagnosticSeverity.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.itsaky.lsp; - -import android.R; -import android.content.Context; - -public class DiagnosticSeverity { - public static final int - - Error = 1, - Warning = 2, - Information = 3, - Hint = 4; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DiagnosticTag.java b/lsp/src/main/java/com/itsaky/lsp/DiagnosticTag.java deleted file mode 100644 index b487c2efd..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DiagnosticTag.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.itsaky.lsp; - -public class DiagnosticTag { - public static final int Unnecessary = 1; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DidChangeConfigurationParams.java b/lsp/src/main/java/com/itsaky/lsp/DidChangeConfigurationParams.java deleted file mode 100644 index 9023d708e..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DidChangeConfigurationParams.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonElement; -import com.google.gson.annotations.SerializedName; - -public class DidChangeConfigurationParams { - @SerializedName("settings") - public JsonElement settings; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DidChangeTextDocumentParams.java b/lsp/src/main/java/com/itsaky/lsp/DidChangeTextDocumentParams.java deleted file mode 100644 index dd2f75b97..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DidChangeTextDocumentParams.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.ArrayList; -import java.util.List; - -public class DidChangeTextDocumentParams { - @SerializedName("textDocument") - public VersionedTextDocumentIdentifier textDocument = new VersionedTextDocumentIdentifier(); - - @SerializedName("contentChanges") - public List contentChanges = new ArrayList<>(); -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DidChangeWatchedFilesParams.java b/lsp/src/main/java/com/itsaky/lsp/DidChangeWatchedFilesParams.java deleted file mode 100644 index 8b5faa6a3..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DidChangeWatchedFilesParams.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.List; -import java.util.ArrayList; - -public class DidChangeWatchedFilesParams { - - @SerializedName("changes") - public List changes = new ArrayList<>(); - - public DidChangeWatchedFilesParams(List changes) { - this.changes = changes; - } - - public DidChangeWatchedFilesParams() { - changes = new ArrayList<>(); - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DidChangeWorkspaceFoldersParams.java b/lsp/src/main/java/com/itsaky/lsp/DidChangeWorkspaceFoldersParams.java deleted file mode 100644 index 0b405ba55..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DidChangeWorkspaceFoldersParams.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class DidChangeWorkspaceFoldersParams { - @SerializedName("event") - public WorkspaceFoldersChangeEvent event; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DidCloseTextDocumentParams.java b/lsp/src/main/java/com/itsaky/lsp/DidCloseTextDocumentParams.java deleted file mode 100644 index da0c8dc3d..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DidCloseTextDocumentParams.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class DidCloseTextDocumentParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument = new TextDocumentIdentifier(); -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DidOpenTextDocument.java b/lsp/src/main/java/com/itsaky/lsp/DidOpenTextDocument.java deleted file mode 100644 index 1fba00e03..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DidOpenTextDocument.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class DidOpenTextDocument { - @SerializedName("textDocument") - public TextDocumentItem textDocument; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DidOpenTextDocumentParams.java b/lsp/src/main/java/com/itsaky/lsp/DidOpenTextDocumentParams.java deleted file mode 100644 index df43554df..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DidOpenTextDocumentParams.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class DidOpenTextDocumentParams { - - @SerializedName("textDocument") - public TextDocumentItem textDocument = new TextDocumentItem(); - - public DidOpenTextDocumentParams() {} - - public DidOpenTextDocumentParams(TextDocumentItem textDocument) { - this.textDocument = textDocument; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DidSaveTextDocumentParams.java b/lsp/src/main/java/com/itsaky/lsp/DidSaveTextDocumentParams.java deleted file mode 100644 index a6e1f779c..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DidSaveTextDocumentParams.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class DidSaveTextDocumentParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; - - @SerializedName("text") - public String text; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DocumentFormattingParams.java b/lsp/src/main/java/com/itsaky/lsp/DocumentFormattingParams.java deleted file mode 100644 index d51dcd50e..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DocumentFormattingParams.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class DocumentFormattingParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; - - @SerializedName("options") - public FormattingOptions options; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DocumentHighlight.java b/lsp/src/main/java/com/itsaky/lsp/DocumentHighlight.java deleted file mode 100644 index c0835068e..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DocumentHighlight.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class DocumentHighlight { - - @SerializedName("range") - public Range range; - - @SerializedName("kind") - public int kind; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DocumentHighlightKind.java b/lsp/src/main/java/com/itsaky/lsp/DocumentHighlightKind.java deleted file mode 100644 index 4a31d8ded..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DocumentHighlightKind.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.itsaky.lsp; - -public class DocumentHighlightKind { - public static final int Text = 1, Read = 2, Write = 3; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DocumentLink.java b/lsp/src/main/java/com/itsaky/lsp/DocumentLink.java deleted file mode 100644 index 26c8625f3..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DocumentLink.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonArray; -import com.google.gson.annotations.SerializedName; - -public class DocumentLink { - - @SerializedName("range") - public Range range; - - @SerializedName("target") - public String target; - - @SerializedName("data") - public JsonArray data; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DocumentLinkParams.java b/lsp/src/main/java/com/itsaky/lsp/DocumentLinkParams.java deleted file mode 100644 index aed2e6d3c..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DocumentLinkParams.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class DocumentLinkParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; - - public DocumentLinkParams() {} - - public DocumentLinkParams(TextDocumentIdentifier textDocument) { - this.textDocument = textDocument; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DocumentSymbol.java b/lsp/src/main/java/com/itsaky/lsp/DocumentSymbol.java deleted file mode 100644 index f330a7370..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DocumentSymbol.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class DocumentSymbol { - @SerializedName("name") - public String name; - - @SerializedName("detail") - public String detail; - - @SerializedName("kind") - public int kind; - - @SerializedName("deprecated") - public boolean deprecated; - - @SerializedName("range") - public Range range; - - @SerializedName("selectionRange") - public Range selectionRange; - - @SerializedName("children") - public List children; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/DocumentSymbolParams.java b/lsp/src/main/java/com/itsaky/lsp/DocumentSymbolParams.java deleted file mode 100644 index dfef84877..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/DocumentSymbolParams.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class DocumentSymbolParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; - - public DocumentSymbolParams() {} - - public DocumentSymbolParams(TextDocumentIdentifier textDocument) { - this.textDocument = textDocument; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/ErrorCodes.java b/lsp/src/main/java/com/itsaky/lsp/ErrorCodes.java deleted file mode 100644 index 38c8554c4..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/ErrorCodes.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.itsaky.lsp; - -public class ErrorCodes { - public static final int ParseError = -32700, - InvalidRequest = -32600, - MethodNotFound = -32601, - InvalidParams = -32602, - InternalError = -32603, - serverErrorStart = -32099, - serverErrorEnd = -32000, - ServerNotInitialized = -32002, - UnknownErrorCode = -32001, - - // TODO comment doesn't highlight properly - // Defined by the protocol. - RequestCancelled = -32800, - ContentModified = -32801; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/FileChangeType.java b/lsp/src/main/java/com/itsaky/lsp/FileChangeType.java deleted file mode 100644 index d9393711a..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/FileChangeType.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.itsaky.lsp; - -public class FileChangeType { - public static final int Created = 1, Changed = 2, Deleted = 3; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/FileEvent.java b/lsp/src/main/java/com/itsaky/lsp/FileEvent.java deleted file mode 100644 index 56bfd44fd..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/FileEvent.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.net.URI; - -public class FileEvent { - - @SerializedName("uri") - public URI uri; - - @SerializedName("type") - public int type; - - public FileEvent(URI uri, int type) { - this.uri = uri; - this.type = type; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/FoldingRange.java b/lsp/src/main/java/com/itsaky/lsp/FoldingRange.java deleted file mode 100644 index 3122117a7..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/FoldingRange.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class FoldingRange { - @SerializedName("startLine") - public int startLine; - - @SerializedName("startCharacter") - public int startCharacter; - - @SerializedName("endLine") - public int endLine; - - @SerializedName("endCharacter") - public int endCharacter; - - @SerializedName("kind") - public String kind; - - public FoldingRange() {} - - public FoldingRange(int startLine, int startCharacter, int endLine, int endCharacter, String kind) { - this.startLine = startLine; - this.startCharacter = startCharacter; - this.endLine = endLine; - this.endCharacter = endCharacter; - this.kind = kind; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/FoldingRangeKind.java b/lsp/src/main/java/com/itsaky/lsp/FoldingRangeKind.java deleted file mode 100644 index eac05a80e..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/FoldingRangeKind.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.itsaky.lsp; - -public class FoldingRangeKind { - /** Folding range for a comment */ - public static final String Comment = "comment"; - /** Folding range for a imports or includes */ - public static final String Imports = "imports"; - /** Folding range for a region (e.g. `#region`) */ - public static final String Region = "region"; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/FoldingRangeParams.java b/lsp/src/main/java/com/itsaky/lsp/FoldingRangeParams.java deleted file mode 100644 index 8b3e41c4c..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/FoldingRangeParams.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class FoldingRangeParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/FormattingOptions.java b/lsp/src/main/java/com/itsaky/lsp/FormattingOptions.java deleted file mode 100644 index c2a41eee6..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/FormattingOptions.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class FormattingOptions { - - @SerializedName("tabSize") - public int tabSize; - - @SerializedName("insertSpaces") - public boolean insertSpaces; - - public FormattingOptions(){} - - public FormattingOptions(int tabSize, boolean insertSpaces) { - this.tabSize = tabSize; - this.insertSpaces = insertSpaces; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/Hover.java b/lsp/src/main/java/com/itsaky/lsp/Hover.java deleted file mode 100644 index ef6b001a1..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/Hover.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class Hover { - @SerializedName("contents") - public List contents; - - @SerializedName("range") - public Range range; - - public Hover() {} - - public Hover(List contents) { - this.contents = contents; - } - - public Hover(List contents, Range range) { - this.contents = contents; - this.range = range; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/InitializeParams.java b/lsp/src/main/java/com/itsaky/lsp/InitializeParams.java deleted file mode 100644 index db69cfebc..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/InitializeParams.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonElement; -import com.google.gson.annotations.SerializedName; -import java.net.URI; -import java.util.List; -import java.util.Set; - -public class InitializeParams { - @SerializedName("processId") - public int processId; - - @SerializedName("rootPath") - public String rootPath; - - @SerializedName("rootUri") - public URI rootUri; - - @SerializedName("roots") - public Set roots; - - @SerializedName("initializationOptions") - public JsonElement initializationOptions; - - @SerializedName("trace") - public String trace; - - @SerializedName("workspaceFolders") - public List workspaceFolders; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/InitializeResult.java b/lsp/src/main/java/com/itsaky/lsp/InitializeResult.java deleted file mode 100644 index f7ae45238..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/InitializeResult.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonObject; -import com.google.gson.annotations.SerializedName; - -public class InitializeResult { - - @SerializedName("capabilities") - public JsonObject capabilities; - - public InitializeResult() {} - - public InitializeResult(JsonObject capabilities) { - this.capabilities = capabilities; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/InsertTextFormat.java b/lsp/src/main/java/com/itsaky/lsp/InsertTextFormat.java deleted file mode 100644 index 8cea8e008..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/InsertTextFormat.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.itsaky.lsp; - -public class InsertTextFormat { - public static final int PlainText = 1, Snippet = 2; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/JavaColors.java b/lsp/src/main/java/com/itsaky/lsp/JavaColors.java deleted file mode 100644 index efaac2223..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/JavaColors.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.itsaky.lsp; -import com.google.gson.GsonBuilder; -import com.google.gson.annotations.SerializedName; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -/** - * A class which stores the syntax highlighting colors obtained from JLS - */ -public class JavaColors { - - @SerializedName("uri") - public URI uri; - - @SerializedName("packages") - public List packages; - - @SerializedName("enumTypes") - public List enumTypes; - - @SerializedName("classNames") - public List classNames; - - @SerializedName("annotationTypes") - public List annotationTypes; - - @SerializedName("interfaces") - public List interfaces; - - @SerializedName("enums") - public List enums; - - @SerializedName("statics") - public List statics; - - @SerializedName("fields") - public List fields; - - @SerializedName("parameters") - public List parameters; - - @SerializedName("locals") - public List locals; - - @SerializedName("exceptionParams") - public List exceptionParams; - - @SerializedName("methods") - public List methods; - - @SerializedName("constructors") - public List constructors; - - @SerializedName("staticInits") - public List staticInits; - - @SerializedName("instanceInits") - public List instanceInits; - - @SerializedName("typeParams") - public List typeParams; - - @SerializedName("resourceVariables") - public List resourceVariables; - - @Override - public String toString() { - return new GsonBuilder().setPrettyPrinting().create().toJson(this); - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/JavaReportProgressParams.java b/lsp/src/main/java/com/itsaky/lsp/JavaReportProgressParams.java deleted file mode 100644 index c63ecfff8..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/JavaReportProgressParams.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class JavaReportProgressParams { - @SerializedName("message") - private String message; - - @SerializedName("increment") - private int increment = -1; - - public JavaReportProgressParams() {} - - public JavaReportProgressParams(String message) { - this.message = message; - } - - public JavaReportProgressParams(String message, int increment) { - this.message = message; - this.increment = increment; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public int getIncrement() { - return increment; - } - - public void setIncrement(int increment) { - this.increment = increment; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/JavaStartProgressParams.java b/lsp/src/main/java/com/itsaky/lsp/JavaStartProgressParams.java deleted file mode 100644 index cfb7967c2..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/JavaStartProgressParams.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class JavaStartProgressParams { - - @SerializedName("message") - private String message; - - public JavaStartProgressParams() {} - - public JavaStartProgressParams(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/LanguageClient.java b/lsp/src/main/java/com/itsaky/lsp/LanguageClient.java deleted file mode 100644 index a3263081f..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/LanguageClient.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonElement; -import java.io.File; -import java.util.List; - -public interface LanguageClient { - void javaProgressStart(JavaStartProgressParams params); - void javaProgressReport(JavaReportProgressParams params); - void javaProgressEnd(); - - void publishDiagnostics(PublishDiagnosticsParams params); - - void gotoDefinition(List locations); - void references(List references); - void signatureHelp(SignatureHelp signature, File file); - void javaColors(JavaColors colors); - - void showMessage(ShowMessageParams params); - void customNotification(String method, JsonElement params); - - void registerCapability(String method, JsonElement options); - - void onServerStarted(int currentId); -} diff --git a/lsp/src/main/java/com/itsaky/lsp/LanguageServer.java b/lsp/src/main/java/com/itsaky/lsp/LanguageServer.java deleted file mode 100644 index eff5c5c00..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/LanguageServer.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.itsaky.lsp; - -import java.util.List; -import java.util.Optional; - -public class LanguageServer { - public InitializeResult initialize(InitializeParams params) { - throw new RuntimeException("Unimplemented"); - } - - public void initialized() { - throw new RuntimeException("Unimplemented"); - } - - public void shutdown() { - throw new RuntimeException("Unimplemented"); - } - - public void didChangeConfiguration(DidChangeConfigurationParams params) { - throw new RuntimeException("Unimplemented"); - } - - public void didOpenTextDocument(DidOpenTextDocumentParams params) { - throw new RuntimeException("Unimplemented"); - } - - public void didChangeTextDocument(DidChangeTextDocumentParams params) { - throw new RuntimeException("Unimplemented"); - } - - public void willSaveTextDocument(WillSaveTextDocumentParams params) { - throw new RuntimeException("Unimplemented"); - } - - public List willSaveWaitUntilTextDocument(WillSaveTextDocumentParams params) { - throw new RuntimeException("Unimplemented"); - } - - public void didSaveTextDocument(DidSaveTextDocumentParams params) { - throw new RuntimeException("Unimplemented"); - } - - public void didCloseTextDocument(DidCloseTextDocumentParams params) { - throw new RuntimeException("Unimplemented"); - } - - public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) { - throw new RuntimeException("Unimplemented"); - } - - public Optional completion(TextDocumentPositionParams params) { - throw new RuntimeException("Unimplemented"); - } - - public CompletionItem resolveCompletionItem(CompletionItem params) { - throw new RuntimeException("Unimplemented"); - } - - public Optional hover(TextDocumentPositionParams params) { - throw new RuntimeException("Unimplemented"); - } - - public Optional signatureHelp(TextDocumentPositionParams params) { - throw new RuntimeException("Unimplemented"); - } - - public Optional> gotoDefinition(TextDocumentPositionParams params) { - throw new RuntimeException("Unimplemented"); - } - - public Optional> findReferences(ReferenceParams params) { - throw new RuntimeException("Unimplemented"); - } - - public List documentSymbol(DocumentSymbolParams params) { - throw new RuntimeException("Unimplemented"); - } - - public List workspaceSymbols(WorkspaceSymbolParams params) { - throw new RuntimeException("Unimplemented"); - } - - public List codeAction(CodeActionParams params) { - throw new RuntimeException("Unimplemented"); - } - - public List codeLens(CodeLensParams params) { - throw new RuntimeException("Unimplemented"); - } - - public CodeLens resolveCodeLens(CodeLens params) { - throw new RuntimeException("Unimplemented"); - } - - public Optional prepareRename(TextDocumentPositionParams params) { - throw new RuntimeException("Unimplemented"); - } - - public WorkspaceEdit rename(RenameParams params) { - throw new RuntimeException("Unimplemented"); - } - - public void didChangeWorkspaceFolders(DidChangeWorkspaceFoldersParams params) { - throw new RuntimeException("Unimplemented"); - } - - public List formatting(DocumentFormattingParams params) { - throw new RuntimeException("Unimplemented"); - } - - public List foldingRange(FoldingRangeParams params) { - throw new RuntimeException("Unimplemented"); - } - - public List documentLink(DocumentLinkParams params) { - throw new RuntimeException("Unimplemented"); - } - - public void doAsyncWork() {} -} diff --git a/lsp/src/main/java/com/itsaky/lsp/Location.java b/lsp/src/main/java/com/itsaky/lsp/Location.java deleted file mode 100644 index 03c060144..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/Location.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.net.URI; -import com.google.gson.GsonBuilder; - -public class Location { - @SerializedName("uri") - public URI uri; - - @SerializedName("range") - public Range range; - - public Location() {} - - public Location(URI uri, Range range) { - this.uri = uri; - this.range = range; - } - - @Override - public String toString() { - return new GsonBuilder().setPrettyPrinting().create().toJson(this); - } - - public static final Location NONE = new Location(null, Range.NONE); -} diff --git a/lsp/src/main/java/com/itsaky/lsp/MarkedString.java b/lsp/src/main/java/com/itsaky/lsp/MarkedString.java deleted file mode 100644 index f274ab575..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/MarkedString.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; -import com.google.gson.annotations.SerializedName; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; - -@JsonAdapter(MarkedString.Adapter.class) -public class MarkedString { - @SerializedName("language") - public String language; - - @SerializedName("value") - public String value; - - public MarkedString() {} - - public MarkedString(String value) { - this.value = value; - } - - public MarkedString(String language, String value) { - this.language = language; - this.value = value; - } - - public static class Adapter extends TypeAdapter { - @Override - public void write(JsonWriter out, MarkedString markedString) throws IOException { - if (markedString.language == null) { - out.value(markedString.value); - } else { - out.beginObject(); - out.name("language"); - out.value(markedString.language); - out.name("value"); - out.value(markedString.value); - out.endObject(); - } - } - - @Override - public MarkedString read(JsonReader reader) throws IOException { - throw new UnsupportedOperationException("Deserializing MarkedString's is unsupported."); - } - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/MarkupContent.java b/lsp/src/main/java/com/itsaky/lsp/MarkupContent.java deleted file mode 100644 index 35c18fb94..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/MarkupContent.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class MarkupContent { - @SerializedName("kind") - public String kind; - - @SerializedName("value") - public String value; - - public MarkupContent() {} - - public MarkupContent(String kind, String value) { - this.kind = kind; - this.value = value; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/MarkupKind.java b/lsp/src/main/java/com/itsaky/lsp/MarkupKind.java deleted file mode 100644 index e1e9bb904..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/MarkupKind.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.itsaky.lsp; - -public class MarkupKind { - public static final String PlainText = "plaintext", Markdown = "markdown"; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/Message.java b/lsp/src/main/java/com/itsaky/lsp/Message.java deleted file mode 100644 index 2231f39e3..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/Message.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonElement; -import com.google.gson.annotations.SerializedName; - -public class Message { - @SerializedName("jsonrpc") - public String jsonrpc; - - @SerializedName("id") - public Integer id; - - @SerializedName("method") - public String method; - - @SerializedName("params") - public JsonElement params; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/MessageType.java b/lsp/src/main/java/com/itsaky/lsp/MessageType.java deleted file mode 100644 index 08881ac68..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/MessageType.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -public class MessageType { - /** An error message. */ - public static final int Error = 1; - /** A warning message. */ - public static final int Warning = 2; - /** An information message. */ - public static final int Info = 3; - /** A log message. */ - public static final int Log = 4; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/NotificationMessage.java b/lsp/src/main/java/com/itsaky/lsp/NotificationMessage.java deleted file mode 100644 index 91ebf0b11..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/NotificationMessage.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonElement; -import com.google.gson.annotations.SerializedName; - -public class NotificationMessage { - - @SerializedName("method") - public String method; - - @SerializedName("params") - public JsonElement params; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/ParameterInformation.java b/lsp/src/main/java/com/itsaky/lsp/ParameterInformation.java deleted file mode 100644 index 5420a76b7..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/ParameterInformation.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class ParameterInformation { - @SerializedName("label") - public String label; - - @SerializedName("documentation") - public MarkupContent documentation; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/Position.java b/lsp/src/main/java/com/itsaky/lsp/Position.java deleted file mode 100644 index 6aef16b78..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/Position.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.GsonBuilder; -import com.google.gson.annotations.SerializedName; - -public class Position { - - @SerializedName("line") - public int line; - - @SerializedName("character") - public int column; - - public Position() {} - - public Position(int line, int character) { - this.line = line; - this.column = character; - } - - @Override - public String toString() { - return new GsonBuilder().setPrettyPrinting().create().toJson(this); - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof Position) { - Position that = (Position) obj; - return this.line == that.line - && this.column == that.column; - } - return false; - } - - public static final Position NONE = new Position(-1, -1); -} diff --git a/lsp/src/main/java/com/itsaky/lsp/PublishDiagnosticsParams.java b/lsp/src/main/java/com/itsaky/lsp/PublishDiagnosticsParams.java deleted file mode 100644 index 8fce25cd6..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/PublishDiagnosticsParams.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -public class PublishDiagnosticsParams { - - @SerializedName("uri") - public URI uri; - - @SerializedName("diagnostics") - public List diagnostics; - - public PublishDiagnosticsParams() { - diagnostics = new ArrayList<>(); - } - - public PublishDiagnosticsParams(URI uri, List diagnostics) { - this.uri = uri; - this.diagnostics = diagnostics; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/Range.java b/lsp/src/main/java/com/itsaky/lsp/Range.java deleted file mode 100644 index e4e259868..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/Range.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.GsonBuilder; -import com.google.gson.annotations.SerializedName; - -public class Range { - @SerializedName("start") - public Position start; - - @SerializedName("end") - public Position end; - - public Range() {} - - public Range(Position start, Position end) { - this.start = start; - this.end = end; - } - - @Override - public String toString() { - return new GsonBuilder().setPrettyPrinting().create().toJson(this); - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof Range) { - Range that = (Range) obj; - return this.start.equals(that.start) - && this.end.equals(that.end); - } - return false; - } - - public static Range ofZero() { - return new Range(new Position(0, 0), new Position(0, 0)); - } - - public static final Range NONE = new Range(Position.NONE, Position.NONE); -} diff --git a/lsp/src/main/java/com/itsaky/lsp/ReferenceContext.java b/lsp/src/main/java/com/itsaky/lsp/ReferenceContext.java deleted file mode 100644 index 06dad5742..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/ReferenceContext.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class ReferenceContext { - - @SerializedName("includeDeclaration") - public boolean includeDeclaration; - - public ReferenceContext(){} - - public ReferenceContext(boolean includeDeclaration) { - this.includeDeclaration = includeDeclaration; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/ReferenceParams.java b/lsp/src/main/java/com/itsaky/lsp/ReferenceParams.java deleted file mode 100644 index 51cbd32ef..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/ReferenceParams.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class ReferenceParams extends TextDocumentPositionParams { - - @SerializedName("context") - public ReferenceContext context; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/RegistrationParams.java b/lsp/src/main/java/com/itsaky/lsp/RegistrationParams.java deleted file mode 100644 index ea6b65126..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/RegistrationParams.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonElement; -import com.google.gson.annotations.SerializedName; - -public class RegistrationParams { - - @SerializedName("id") - public String id; - - @SerializedName("method") - public String method; - - @SerializedName("registerOptions") - public JsonElement registerOptions; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/RenameParams.java b/lsp/src/main/java/com/itsaky/lsp/RenameParams.java deleted file mode 100644 index 4676cf13d..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/RenameParams.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.itsaky.lsp; - - -import com.google.gson.annotations.SerializedName; - -public class RenameParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; - - @SerializedName("position") - public Position position; - - @SerializedName("newName") - public String newName; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/RenameResponse.java b/lsp/src/main/java/com/itsaky/lsp/RenameResponse.java deleted file mode 100644 index e2132b940..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/RenameResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class RenameResponse { - - @SerializedName("range") - public Range range; - - @SerializedName("placeholder") - public String placeholder; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/RequestMessage.java b/lsp/src/main/java/com/itsaky/lsp/RequestMessage.java deleted file mode 100644 index c16d1d3ea..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/RequestMessage.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.JsonElement; -import com.google.gson.annotations.SerializedName; - -public class RequestMessage { - - @SerializedName("id") - public String id; - - @SerializedName("method") - public String method; - - @SerializedName("params") - public JsonElement params; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/ResponseError.java b/lsp/src/main/java/com/itsaky/lsp/ResponseError.java deleted file mode 100644 index 14e1086d9..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/ResponseError.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class ResponseError { - - @SerializedName("code") - public int code; - - @SerializedName("message") - public String message; - - @SerializedName("data") - public Object data; - - public ResponseError() {} - - public ResponseError(int code, String message, Object data) { - this.code = code; - this.message = message; - this.data = data; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/ShowMessageParams.java b/lsp/src/main/java/com/itsaky/lsp/ShowMessageParams.java deleted file mode 100644 index 4a366a0a5..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/ShowMessageParams.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class ShowMessageParams { - - @SerializedName("type") - public int type; - - @SerializedName("message") - public String message; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/SignatureHelp.java b/lsp/src/main/java/com/itsaky/lsp/SignatureHelp.java deleted file mode 100644 index 81d6edc97..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/SignatureHelp.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class SignatureHelp { - @SerializedName("signatures") - public List signatures; - - @SerializedName("activeSignature") - public Integer activeSignature; - - @SerializedName("activeParameter") - public Integer activeParameter; - - public SignatureHelp() {} - - public SignatureHelp(List signatures, Integer activeSignature, Integer activeParameter) { - this.signatures = signatures; - this.activeSignature = activeSignature; - this.activeParameter = activeParameter; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/SignatureInformation.java b/lsp/src/main/java/com/itsaky/lsp/SignatureInformation.java deleted file mode 100644 index 205253081..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/SignatureInformation.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class SignatureInformation { - - @SerializedName("label") - public String label; - - @SerializedName("documentation") - public MarkupContent documentation; - - @SerializedName("parameters") - public List parameters; - - public SignatureInformation() {} - - public SignatureInformation(String label, MarkupContent documentation, List parameters) { - this.label = label; - this.documentation = documentation; - this.parameters = parameters; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/SymbolInformation.java b/lsp/src/main/java/com/itsaky/lsp/SymbolInformation.java deleted file mode 100644 index b9475b8df..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/SymbolInformation.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class SymbolInformation { - - @SerializedName("name") - public String name; - - @SerializedName("kind") - public int kind; - - @SerializedName("deprecated") - public boolean deprecated; - - @SerializedName("location") - public Location location; - - @SerializedName("containerName") - public String containerName; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/SymbolKind.java b/lsp/src/main/java/com/itsaky/lsp/SymbolKind.java deleted file mode 100644 index 2a78ee76a..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/SymbolKind.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.itsaky.lsp; - -public class SymbolKind { - public static final int File = 1, - Module = 2, - Namespace = 3, - Package = 4, - Class = 5, - Method = 6, - Property = 7, - Field = 8, - Constructor = 9, - Enum = 10, - Interface = 11, - Function = 12, - Variable = 13, - Constant = 14, - String = 15, - Number = 16, - Boolean = 17, - Array = 18, - Object = 19, - Key = 20, - Null = 21, - EnumMember = 22, - Struct = 23, - Event = 24, - Operator = 25, - TypeParameter = 26; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/TextDocumentContentChangeEvent.java b/lsp/src/main/java/com/itsaky/lsp/TextDocumentContentChangeEvent.java deleted file mode 100644 index b38a0981f..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/TextDocumentContentChangeEvent.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class TextDocumentContentChangeEvent { - @SerializedName("range") - public Range range; - - @SerializedName("rangeLength") - public Integer rangeLength; - - @SerializedName("text") - public String text; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/TextDocumentEdit.java b/lsp/src/main/java/com/itsaky/lsp/TextDocumentEdit.java deleted file mode 100644 index d7f53a2c9..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/TextDocumentEdit.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class TextDocumentEdit { - @SerializedName("textDocument") - public VersionedTextDocumentIdentifier textDocument; - - @SerializedName("edits") - public List edits; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/TextDocumentIdentifier.java b/lsp/src/main/java/com/itsaky/lsp/TextDocumentIdentifier.java deleted file mode 100644 index ec26dd51f..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/TextDocumentIdentifier.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.net.URI; - -public class TextDocumentIdentifier { - - @SerializedName("uri") - public URI uri; - - public TextDocumentIdentifier() {} - - public TextDocumentIdentifier(URI uri) { - this.uri = uri; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/TextDocumentItem.java b/lsp/src/main/java/com/itsaky/lsp/TextDocumentItem.java deleted file mode 100644 index c7e9ddd37..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/TextDocumentItem.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.net.URI; - -public class TextDocumentItem { - @SerializedName("uri") - public URI uri; - - @SerializedName("languageId") - public String languageId; - - @SerializedName("version") - public int version; - - @SerializedName("text") - public String text; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/TextDocumentPositionParams.java b/lsp/src/main/java/com/itsaky/lsp/TextDocumentPositionParams.java deleted file mode 100644 index 8f58fd721..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/TextDocumentPositionParams.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class TextDocumentPositionParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; - - @SerializedName("position") - public Position position; - - public TextDocumentPositionParams() {} - - public TextDocumentPositionParams(TextDocumentIdentifier textDocument, Position position) { - this.textDocument = textDocument; - this.position = position; - } -} diff --git a/lsp/src/main/java/com/itsaky/lsp/TextDocumentSaveReason.java b/lsp/src/main/java/com/itsaky/lsp/TextDocumentSaveReason.java deleted file mode 100644 index fd2c65069..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/TextDocumentSaveReason.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.itsaky.lsp; - -public class TextDocumentSaveReason { - public static final int Manual = 1, AfterDelay = 2, FocusOut = 3; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/TextEdit.java b/lsp/src/main/java/com/itsaky/lsp/TextEdit.java deleted file mode 100644 index 0c0df87a9..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/TextEdit.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.itsaky.lsp; -import com.google.gson.GsonBuilder; -import com.google.gson.annotations.SerializedName; - -public class TextEdit { - - @SerializedName("range") - public Range range; - - @SerializedName("newText") - public String newText; - - public TextEdit() {} - - public TextEdit(Range range, String newText) { - this.range = range; - this.newText = newText; - } - - @Override - public String toString() { - return new GsonBuilder().setPrettyPrinting().create().toJson(this); - } - - public static final TextEdit NONE = new TextEdit(Range.NONE, ""); -} diff --git a/lsp/src/main/java/com/itsaky/lsp/VersionedTextDocumentIdentifier.java b/lsp/src/main/java/com/itsaky/lsp/VersionedTextDocumentIdentifier.java deleted file mode 100644 index 1511359b2..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/VersionedTextDocumentIdentifier.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.net.URI; - -public class VersionedTextDocumentIdentifier { - @SerializedName("uri") - public URI uri; - - @SerializedName("version") - public int version; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/WillSaveTextDocumentParams.java b/lsp/src/main/java/com/itsaky/lsp/WillSaveTextDocumentParams.java deleted file mode 100644 index febc59788..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/WillSaveTextDocumentParams.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; - -public class WillSaveTextDocumentParams { - - @SerializedName("textDocument") - public TextDocumentIdentifier textDocument; - - @SerializedName("reason") - public int reason; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/WorkspaceEdit.java b/lsp/src/main/java/com/itsaky/lsp/WorkspaceEdit.java deleted file mode 100644 index f4993d6f0..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/WorkspaceEdit.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.net.URI; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class WorkspaceEdit { - @SerializedName("changes") - public Map> changes = new HashMap<>(); -} diff --git a/lsp/src/main/java/com/itsaky/lsp/WorkspaceFolder.java b/lsp/src/main/java/com/itsaky/lsp/WorkspaceFolder.java deleted file mode 100644 index 6bdc6b89c..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/WorkspaceFolder.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.net.URI; - -public class WorkspaceFolder { - - @SerializedName("uri") - public URI uri; - - @SerializedName("name") - public String name; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/WorkspaceFoldersChangeEvent.java b/lsp/src/main/java/com/itsaky/lsp/WorkspaceFoldersChangeEvent.java deleted file mode 100644 index 9983a362b..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/WorkspaceFoldersChangeEvent.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.itsaky.lsp; - -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class WorkspaceFoldersChangeEvent { - @SerializedName("added") - public List added; - - @SerializedName("removed") - public List removed; -} diff --git a/lsp/src/main/java/com/itsaky/lsp/WorkspaceSymbolParams.java b/lsp/src/main/java/com/itsaky/lsp/WorkspaceSymbolParams.java deleted file mode 100644 index cdf347886..000000000 --- a/lsp/src/main/java/com/itsaky/lsp/WorkspaceSymbolParams.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.itsaky.lsp; -import com.google.gson.annotations.SerializedName; - -public class WorkspaceSymbolParams { - - @SerializedName("query") - public String query; - - public WorkspaceSymbolParams() {} - - public WorkspaceSymbolParams(String query) { - this.query = query; - } -} diff --git a/settings.gradle b/settings.gradle index 1b61030ba..4390631de 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,5 @@ include ':app' include ':treeview' -include ':lsp' include ':emulatorview' include ':emulator' include ':javapoet'