From 4d6bd78652590733de23155b5caa6e4c0f8d8376 Mon Sep 17 00:00:00 2001 From: Kanro Date: Wed, 12 Jun 2024 04:03:01 +0800 Subject: [PATCH] Protobuf Editions support (#254) --- .github/workflows/build.yml | 221 +++++-- .github/workflows/release.yml | 49 +- .run/Run IDE with Plugin.run.xml | 46 +- .run/Run Plugin.run.xml | 30 + .run/Run Tests.run.xml | 56 +- CHANGELOG.md | 33 +- README.md | 9 +- build.gradle.kts | 190 +++--- gradle.properties | 28 +- gradle/libs.versions.toml | 22 + gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 61608 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 269 ++++---- gradlew.bat | 15 +- qodana.yml | 8 +- settings.gradle.kts | 4 + src/main/grammar/protobuf.bnf | 572 ++++++++++++------ src/main/grammar/protobuf.flex | 6 +- src/main/grammar/prototext.bnf | 205 +++++++ src/main/grammar/prototext.flex | 130 ++++ .../lang/parser/ProtobufParserUtil.java | 6 +- .../idea/plugin/protobuf/ProtobufIcons.kt | 1 + .../idea/plugin/protobuf/aip/Extension.kt | 9 +- .../protobuf/aip/annotator/AipAnnotator.kt | 9 +- .../completion/AipCompletionContributor.kt | 8 +- .../protobuf/aip/method/AipSpecMethod.kt | 2 +- .../aip/quickfix/AddResourceImportFix.kt | 14 +- .../aip/reference/AipResourceReference.kt | 18 +- .../aip/reference/AipResourceResolver.kt | 15 +- .../aip/reference/AipTypeNameReference.kt | 140 +++++ .../ProtobufFieldReferenceInString.kt | 28 +- .../contributor/AipReferenceContributor.kt | 62 +- .../ProtobufTypeNameInStringProvider.kt | 220 ++++--- .../idea/plugin/protobuf/compile/Protoc.kt | 6 +- .../idea/plugin/protobuf/compile/States.kt | 20 +- .../protobuf/compile/basic/EnumCompiler.kt | 2 +- .../protobuf/compile/basic/FileCompiler.kt | 9 +- .../protobuf/compile/basic/MessageCompiler.kt | 33 +- .../protobuf/compile/basic/ServiceCompiler.kt | 10 +- .../plugin/protobuf/golang/GoIndexProvider.kt | 10 +- .../protobuf/golang/GoLineMarkerProvider.kt | 4 +- .../plugin/protobuf/golang/GoNameIndex.kt | 2 +- .../golang/GoUnimplementedServerNameIndex.kt | 2 +- .../idea/plugin/protobuf/golang/Names.kt | 33 +- .../kanro/idea/plugin/protobuf/grpc/Utils.kt | 2 +- .../gutter/AipRunRequestGutterProvider.kt | 16 +- .../gutter/GrpcRunRequestGutterProvider.kt | 4 +- .../grpc/index/MessageShortNameIndex.kt | 2 +- .../protobuf/grpc/index/ServiceMethodIndex.kt | 2 +- .../grpc/index/ServiceMethodIndexProvider.kt | 13 +- .../grpc/index/ServiceQualifiedNameIndex.kt | 2 +- .../grpc/index/ServiceShortNameIndex.kt | 2 +- .../protobuf/grpc/referece/Extensions.kt | 9 +- .../referece/GrpcMessageEnumValueReference.kt | 10 +- .../referece/GrpcMessageFieldReference.kt | 15 +- .../grpc/referece/GrpcMethodReference.kt | 4 +- .../grpc/referece/GrpcServiceReference.kt | 6 +- .../referece/GrpcTranscodingQueryReference.kt | 3 +- .../grpc/referece/GrpcTypeUrlReference.kt | 6 +- .../grpc/referece/GrpcUrlReferenceProvider.kt | 6 +- .../grpc/request/GrpcRequestConverter.kt | 13 +- .../grpc/request/GrpcRequestHandler.kt | 2 +- .../grpc/request/ProtoFileReflection.kt | 4 +- .../idea/plugin/protobuf/java/Extension.kt | 14 +- .../protobuf/java/FileJavaOptionsProvider.kt | 32 +- .../protobuf/java/JavaFindUsageFactory.kt | 20 +- .../plugin/protobuf/java/JavaIndexProvider.kt | 10 +- .../protobuf/java/JavaLineMarkerProvider.kt | 7 +- .../plugin/protobuf/java/JavaNameIndex.kt | 2 +- .../kanro/idea/plugin/protobuf/java/Names.kt | 39 +- .../java/ProtobufLineMarkerProvider.kt | 7 +- .../plugin/protobuf/lang/ProtoTextFileType.kt | 33 + .../plugin/protobuf/lang/ProtoTextLanguage.kt | 5 + .../lang/ProtoTextParserDefinition.kt | 53 ++ .../plugin/protobuf/lang/ProtobufFileType.kt | 2 +- .../protobuf/lang/ProtobufParserDefinition.kt | 10 +- .../lang/actions/ArrangeFieldsNumberAction.kt | 12 +- .../protobuf/lang/annotator/FileTracker.kt | 16 +- .../protobuf/lang/annotator/NumberTracker.kt | 33 +- .../lang/annotator/ProtoTextAnnotator.kt | 156 +++++ .../lang/annotator/Protobuf2Annotator.kt | 14 +- .../lang/annotator/Protobuf3Annotator.kt | 38 +- .../lang/annotator/ProtobufAnnotator.kt | 374 +++++------- .../annotator/ProtobufEditionAnnotator.kt | 17 + .../lang/annotator/ProtobufFeature.kt | 73 +++ .../protobuf/lang/annotator/ScopeTracker.kt | 15 +- .../lang/completion/AddImportInsertHandler.kt | 4 +- .../lang/completion/EnumValueNameProvider.kt | 2 +- .../lang/completion/FieldNameProvider.kt | 13 +- .../ProtobufCompletionContributor.kt | 20 +- .../lang/docs/MarkdownSymbolReference.kt | 13 +- .../ProtobufLineCommentsMarkdownInjector.kt | 2 +- .../edting/ProtoTextPairedBraceMatcher.kt | 37 ++ .../lang/edting/ProtoTextQuoteHandler.kt | 6 + .../edting/ProtoTextSpellcheckingStrategy.kt | 21 + .../lang/edting/ProtobufPairedBraceMatcher.kt | 2 +- .../lang/edting/ProtobufQuoteHandler.kt | 2 +- .../edting/ProtobufSpellcheckingStrategy.kt | 2 +- .../lang/folding/ProtobufFoldingBuilder.kt | 14 +- .../lang/formatter/ProtoTextCommenter.kt | 61 ++ .../ProtoTextFormattingModelBuilder.kt | 60 ++ ...toTextLanguageCodeStyleSettingsProvider.kt | 112 ++++ .../protobuf/lang/formatter/ProtobufBlock.kt | 59 +- .../lang/formatter/ProtobufCommenter.kt | 2 +- .../ProtobufFormattingModelBuilder.kt | 7 +- .../lang/formatter/ProtobufImportOptimizer.kt | 83 ++- ...otobufLanguageCodeStyleSettingsProvider.kt | 1 + .../highligh/ProtobufHighlightingAnnotator.kt | 90 --- .../highlight/ProtoTextColorSettingsPage.kt | 80 +++ .../lang/highlight/ProtoTextHighlighter.kt | 122 ++++ .../ProtoTextHighlightingAnnotator.kt | 57 ++ .../highlight/ProtobufColorSettingsPage.kt | 98 +++ .../ProtobufHighlightLexer.kt | 4 +- .../ProtobufHighlighter.kt | 6 +- .../ProtobufHighlightingAnnotator.kt | 99 +++ .../protobuf/lang/lexer/ProtoTextLexer.kt | 6 + .../protobuf/lang/lexer/ProtobufLexer.kt | 1 + .../plugin/protobuf/lang/psi/BaseElement.kt | 5 + .../plugin/protobuf/lang/psi/Extension.kt | 352 +---------- .../protobuf/lang/psi/ProtobufElementType.kt | 6 - .../BodyElement.kt} | 7 +- .../protobuf/lang/psi/feature/BodyOwner.kt | 10 + .../DocumentElement.kt} | 6 +- .../DocumentOwner.kt} | 8 +- .../lang/psi/feature/FoldingElement.kt | 8 + .../lang/psi/feature/LookupableElement.kt | 9 + .../protobuf/lang/psi/feature/NamedElement.kt | 7 + .../structure => feature}/ProtobufNumbered.kt | 5 +- .../lang/psi/feature/QualifiedElement.kt | 13 + .../lang/psi/feature/ReferenceElement.kt | 14 + .../protobuf/lang/psi/feature/ValueAssign.kt | 9 + .../protobuf/lang/psi/feature/ValueElement.kt | 19 + .../psi/mixin/ProtobufBuiltInOptionMixin.kt | 13 - .../lang/psi/mixin/ProtobufEnumValueMixin.kt | 13 - .../lang/psi/mixin/ProtobufFieldNameMixin.kt | 13 - .../psi/mixin/ProtobufStringValueMixin.kt | 17 - .../lang/psi/mixin/ProtobufTypeNameMixin.kt | 74 --- .../primitive/element/ProtobufFieldAssign.kt | 24 - .../element/ProtobufFieldDefinition.kt | 51 -- .../element/ProtobufMapFieldDefinition.kt | 32 - .../primitive/element/ProtobufOptionAssign.kt | 13 - .../ProtobufFileReferenceContributor.kt | 5 - .../psi/primitive/feature/ProtobufFolding.kt | 8 - .../primitive/feature/ProtobufLookupItem.kt | 9 - .../primitive/feature/ProtobufNamedElement.kt | 7 - .../feature/ProtobufSymbolReferenceHost.kt | 54 -- .../primitive/stratify/ProtobufBodyOwner.kt | 10 - .../primitive/stratify/ProtobufOptionHover.kt | 50 -- .../primitive/structure/ProtobufFieldLike.kt | 13 - .../structure/ProtobufValueAssign.kt | 13 - .../structure/ProtobufVirtualScope.kt | 3 - .../lang/psi/primitive/type/ProtobufBlock.kt | 5 - .../psi/primitive/type/ProtobufFragment.kt | 5 - .../psi/primitive/type/ProtobufStatement.kt | 5 - .../psi/{ => proto}/ProtobufASTFactory.kt | 6 +- .../{primitive => proto}/ProtobufElement.kt | 7 +- .../ProtobufElementBase.kt | 6 +- .../lang/psi/proto/ProtobufElementType.kt | 14 + .../lang/psi/proto/ProtobufEnumValue.kt | 26 + .../psi/proto/ProtobufExtensionFieldName.kt | 5 + .../lang/psi/proto/ProtobufExtensionRange.kt | 16 + .../lang/psi/proto/ProtobufFieldName.kt | 43 ++ .../lang/psi/{ => proto}/ProtobufFile.kt | 21 +- .../lang/psi/proto/ProtobufImportStatement.kt | 13 + .../psi/proto/ProtobufMapFieldDefinition.kt | 11 + .../psi/proto/ProtobufMessageDefinition.kt | 137 +++++ .../lang/psi/proto/ProtobufOptionName.kt | 32 + .../{util => psi/proto}/ProtobufPsiFactory.kt | 29 +- .../lang/psi/proto/ProtobufReservedName.kt | 13 + .../lang/psi/proto/ProtobufReservedRange.kt | 16 + .../protobuf/lang/psi/proto/ProtobufRpcIO.kt | 15 + .../lang/psi/proto/ProtobufStringValue.kt | 26 + .../lang/psi/proto/ProtobufTypeName.kt | 5 + .../element/ProtobufEnumDefinition.kt | 10 +- .../element/ProtobufEnumValueDefinition.kt | 6 +- .../element/ProtobufExtendDefinition.kt | 14 +- .../proto/element/ProtobufFieldDefinition.kt | 79 +++ .../element/ProtobufGroupDefinition.kt | 13 +- .../element/ProtobufMapFieldDefinition.kt | 73 +++ .../element/ProtobufMessageDefinition.kt | 11 +- .../element/ProtobufOneofDefinition.kt | 6 +- .../psi/proto/element/ProtobufOptionAssign.kt | 18 + .../element/ProtobufPackageName.kt | 18 +- .../element/ProtobufRpcDefinition.kt | 14 +- .../element/ProtobufServiceDefinition.kt | 8 +- .../psi/proto/feature/ProtobufFieldAssign.kt | 19 + .../ProtobufFileReferenceContributor.kt | 5 + .../feature/ProtobufIndexProvider.kt | 4 +- .../psi/proto/feature/ProtobufOptionHover.kt | 40 ++ .../feature}/ProtobufOptionOwner.kt | 11 +- .../feature/ProtobufStubExternalProvider.kt | 4 +- .../feature/ProtobufStubSupport.kt | 7 +- .../psi/{ => proto}/impl/ProtobufFileImpl.kt | 44 +- .../impl/ProtobufLineCommentImpl.kt | 14 +- .../psi/proto/mixin/ProtobufEnumValueMixin.kt | 17 + .../mixin/ProtobufExtensionFieldNameMixin.kt | 49 ++ .../psi/proto/mixin/ProtobufFieldNameMixin.kt | 29 + .../mixin/ProtobufImportStatementMixin.kt | 8 +- .../mixin/ProtobufMessageDefinitionMixin.kt | 55 +- .../proto/mixin/ProtobufOptionNameMixin.kt | 54 ++ .../proto/mixin/ProtobufStringValueMixin.kt | 27 + .../psi/proto/mixin/ProtobufTypeNameMixin.kt | 49 ++ .../reference/ProtobufEnumValueReference.kt | 12 +- .../ProtobufExtensionFieldReference.kt | 224 +++++++ .../proto/reference/ProtobufFieldReference.kt | 79 +++ .../reference/ProtobufImportReference.kt | 9 +- .../reference/ProtobufOptionNameReference.kt | 138 +++++ .../reference/ProtobufTypeNameReference.kt | 191 ++++++ .../structure/ProtobufDefinition.kt | 16 +- .../psi/proto/structure/ProtobufFieldLike.kt | 36 ++ .../structure/ProtobufMultiNameDefinition.kt | 2 +- .../structure/ProtobufNumberScope.kt | 19 +- .../structure/ProtobufScope.kt | 10 +- .../structure/ProtobufScopeItem.kt | 4 +- .../structure/ProtobufScopeItemContainer.kt | 8 +- .../proto/structure/ProtobufVirtualScope.kt | 3 + .../lang/psi/{ => proto}/stub/ProtobufStub.kt | 14 +- .../stub}/StubBasedProtobufElementBase.kt | 8 +- .../{ => proto}/stub/impl/ProtobufEnumStub.kt | 12 +- .../stub/impl/ProtobufEnumValueStub.kt | 12 +- .../psi/proto/stub/impl/ProtobufExtendStub.kt | 15 + .../stub/impl/ProtobufFieldStub.kt | 10 +- .../stub/impl/ProtobufFileStubImpl.kt | 11 +- .../stub/impl/ProtobufGroupStub.kt | 12 +- .../stub/impl/ProtobufMapFieldStub.kt | 10 +- .../stub/impl/ProtobufMessageStub.kt | 12 +- .../psi/proto/stub/impl/ProtobufOneofStub.kt | 20 + .../stub/impl/ProtobufPackageNameStub.kt | 9 +- .../{ => proto}/stub/impl/ProtobufRpcStub.kt | 12 +- .../stub/impl/ProtobufServiceStub.kt | 16 +- .../{ => proto}/stub/impl/ProtobufStubBase.kt | 9 +- .../stub/index/QualifiedNameIndex.kt | 4 +- .../stub/index/ResourceTypeIndex.kt | 4 +- .../{ => proto}/stub/index/ShortNameIndex.kt | 4 +- .../stub/primitive/ProtobufNamedStub.kt | 2 +- .../stub/type/ProtobufEnumStubType.kt | 8 +- .../stub/type/ProtobufEnumValueStubType.kt | 8 +- .../stub/type/ProtobufExtendStubType.kt | 8 +- .../stub/type/ProtobufFieldStubType.kt | 8 +- .../stub/type/ProtobufGroupStubType.kt | 8 +- .../stub/type/ProtobufMapFieldStubType.kt | 8 +- .../stub/type/ProtobufMessageStubType.kt | 10 +- .../stub/type/ProtobufOneofStubType.kt | 8 +- .../stub/type/ProtobufPackageNameStubType.kt | 8 +- .../stub/type/ProtobufRpcStubType.kt | 8 +- .../stub/type/ProtobufServiceStubType.kt | 8 +- .../stub/type/ProtobufStubTypeBase.kt | 18 +- .../stub/type/ProtobufStubTypes.kt | 2 +- .../{ => proto}/token/ProtobufCommentToken.kt | 2 +- .../{ => proto}/token/ProtobufKeywordToken.kt | 2 +- .../psi/{ => proto}/token/ProtobufToken.kt | 2 +- .../psi/{ => proto}/token/ProtobufTokens.kt | 8 +- .../lang/psi/stub/impl/ProtobufExtendStub.kt | 15 - .../lang/psi/stub/impl/ProtobufOneofStub.kt | 21 - .../lang/psi/text/ProtoTextASTFactory.kt | 21 + .../lang/psi/text/ProtoTextElement.kt | 17 + .../lang/psi/text/ProtoTextElementBase.kt | 32 + .../lang/psi/text/ProtoTextElementType.kt | 6 + .../lang/psi/text/ProtoTextEnumValue.kt | 31 + .../lang/psi/text/ProtoTextFieldName.kt | 39 ++ .../protobuf/lang/psi/text/ProtoTextFile.kt | 48 ++ .../lang/psi/text/ProtoTextPsiFactory.kt | 50 ++ .../lang/psi/text/ProtoTextTypeName.kt | 5 + .../psi/text/feature/ProtoTextFieldAssign.kt | 19 + .../lang/psi/text/impl/ProtoTextFileImpl.kt | 43 ++ .../impl/ProtoTextSharpLineCommentImpl.kt | 22 + .../psi/text/mixin/ProtoTextEnumValueMixin.kt | 13 + .../psi/text/mixin/ProtoTextFieldNameMixin.kt | 31 + .../text/mixin/ProtoTextStringValueMixin.kt | 28 + .../psi/text/mixin/ProtoTextTypeNameMixin.kt | 57 ++ .../reference/ProtoTextEnumValueReference.kt | 41 ++ .../text/reference/ProtoTextFieldReference.kt | 92 +++ .../reference/ProtoTextHeaderFileReference.kt | 91 +++ .../ProtoTextHeaderMessageReference.kt | 60 ++ ...otoTextSharpCommentReferenceContributor.kt | 43 ++ .../reference/ProtoTextTypeNameReference.kt | 193 ++++++ .../psi/text/token/ProtoTextCommentToken.kt | 6 + .../psi/text/token/ProtoTextKeywordToken.kt | 6 + .../lang/psi/text/token/ProtoTextToken.kt | 6 + .../lang/psi/text/token/ProtobufTokens.kt | 102 ++++ .../protobuf/lang/psi/type/BlockElement.kt | 5 + .../protobuf/lang/psi/type/FragmentElement.kt | 5 + .../lang/psi/type/StatementElement.kt | 5 + .../protobuf/lang/psi/value/ArrayValue.kt | 19 + .../protobuf/lang/psi/value/BooleanValue.kt | 10 + .../protobuf/lang/psi/value/EnumValue.kt | 10 + .../protobuf/lang/psi/value/IntegerValue.kt | 10 + .../protobuf/lang/psi/value/MessageValue.kt | 38 ++ .../protobuf/lang/psi/value/NumberValue.kt | 22 + .../protobuf/lang/psi/value/StringValue.kt | 21 + .../protobuf/lang/psi/value/ValueUtils.kt | 61 ++ .../protobuf/lang/psi/value/WrappedValue.kt | 15 + .../protobuf/lang/quickfix/AddImportFix.kt | 43 +- .../lang/quickfix/OptimizeImportsFix.kt | 6 +- .../lang/quickfix/ProtobufAddImportAction.kt | 29 +- .../protobuf/lang/quickfix/RenameFix.kt | 6 +- .../ProtobufBuiltInOptionReference.kt | 108 ---- .../lang/reference/ProtobufFieldReference.kt | 55 -- .../ProtobufGotoSymbolContributor.kt | 4 +- .../ProtobufRefactoringSupportProvider.kt | 4 +- .../lang/reference/ProtobufSymbolFilters.kt | 106 +--- .../ProtobufSymbolReferenceContributor.kt | 94 ++- .../lang/reference/ProtobufSymbolResolver.kt | 21 +- .../reference/ProtobufTypeNameReference.kt | 196 ------ .../plugin/protobuf/lang/support/Options.kt | 1 + .../lang/ui/ProtobufDocumentationProvider.kt | 24 +- .../ui/ProtobufElementDescriptionProvider.kt | 2 +- .../protobuf/lang/ui/ProtobufIconProvider.kt | 24 +- .../lang/ui/ProtobufStructureViewFactory.kt | 6 +- .../lang/usage/ProtobufFindUsageProvider.kt | 4 +- .../lang/usage/ProtobufUsageTypeProvider.kt | 39 +- .../plugin/protobuf/lang/util/CommonMark.kt | 2 +- .../microservices/GrpcEndpointsProvider.kt | 4 +- .../microservices/GrpcUrlTargetInfo.kt | 2 +- .../microservices/model/ProtobufRpcModel.kt | 2 +- .../model/ProtobufServiceModel.kt | 4 +- .../plugin/protobuf/sisyphus/Extensions.kt | 14 +- .../idea/plugin/protobuf/sisyphus/Names.kt | 37 +- .../sisyphus/SisyphusFindUsageFactory.kt | 20 +- .../sisyphus/SisyphusIndexProvider.kt | 9 +- .../SisyphusKotlinLineMarkerProvider.kt | 7 +- .../protobuf/sisyphus/SisyphusNameIndex.kt | 2 +- .../SisyphusProtobufLineMarkerProvider.kt | 7 +- .../kanro/idea/plugin/protobuf/string/Util.kt | 2 + .../string/case/CommonWordSplitter.kt | 16 + src/main/resources/META-INF/plugin.xml | 61 +- .../protobuf/icon/expui/procedure@12x12.svg | 12 +- .../protobuf/icon/expui/procedureHttp.svg | 18 +- .../icon/expui/procedureHttp_dark.svg | 6 +- .../icon/expui/protobuf_text_file.svg | 26 + .../icon/expui/protobuf_text_file_dark.svg | 26 + .../protobuf/icon/protobuf_text_file.svg | 11 + .../protobuf/proto/google/protobuf/any.proto | 10 +- .../protobuf/proto/google/protobuf/api.proto | 5 +- .../proto/google/protobuf/cpp_features.proto | 58 ++ .../proto/google/protobuf/descriptor.proto | 492 +++++++++++++-- .../proto/google/protobuf/duration.proto | 3 +- .../proto/google/protobuf/empty.proto | 3 +- .../proto/google/protobuf/field_mask.proto | 2 +- .../proto/google/protobuf/java_features.proto | 71 +++ .../google/protobuf/source_context.proto | 2 +- .../proto/google/protobuf/struct.proto | 8 +- .../proto/google/protobuf/timestamp.proto | 7 +- .../protobuf/proto/google/protobuf/type.proto | 8 +- .../proto/google/protobuf/wrappers.proto | 4 +- 345 files changed, 7689 insertions(+), 3283 deletions(-) create mode 100644 .run/Run Plugin.run.xml create mode 100644 gradle/libs.versions.toml create mode 100644 src/main/grammar/prototext.bnf create mode 100644 src/main/grammar/prototext.flex create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipTypeNameReference.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextFileType.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextLanguage.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextParserDefinition.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtoTextAnnotator.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufEditionAnnotator.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufFeature.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextPairedBraceMatcher.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextQuoteHandler.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextSpellcheckingStrategy.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextCommenter.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextFormattingModelBuilder.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextLanguageCodeStyleSettingsProvider.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightingAnnotator.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextColorSettingsPage.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlighter.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlightingAnnotator.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufColorSettingsPage.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/{highligh => highlight}/ProtobufHighlightLexer.kt (81%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/{highligh => highlight}/ProtobufHighlighter.kt (96%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightingAnnotator.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtoTextLexer.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/BaseElement.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufElementType.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive/stratify/ProtobufBody.kt => feature/BodyElement.kt} (68%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyOwner.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive/feature/ProtobufDocument.kt => feature/DocumentElement.kt} (75%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive/feature/ProtobufDocumented.kt => feature/DocumentOwner.kt} (59%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/FoldingElement.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/LookupableElement.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/NamedElement.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive/structure => feature}/ProtobufNumbered.kt (61%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/QualifiedElement.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ReferenceElement.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueAssign.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueElement.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufBuiltInOptionMixin.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufEnumValueMixin.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufFieldNameMixin.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufStringValueMixin.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufTypeNameMixin.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldAssign.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldDefinition.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMapFieldDefinition.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOptionAssign.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFileReferenceContributor.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFolding.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufLookupItem.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufNamedElement.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufSymbolReferenceHost.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBodyOwner.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionHover.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufFieldLike.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufValueAssign.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufVirtualScope.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufBlock.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufFragment.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufStatement.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/ProtobufASTFactory.kt (72%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/ProtobufElement.kt (64%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/ProtobufElementBase.kt (83%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementType.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufEnumValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionFieldName.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionRange.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFieldName.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/ProtobufFile.kt (64%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufImportStatement.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMapFieldDefinition.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMessageDefinition.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufOptionName.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/{util => psi/proto}/ProtobufPsiFactory.kt (65%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedName.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedRange.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufRpcIO.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufStringValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufTypeName.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/element/ProtobufEnumDefinition.kt (61%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/element/ProtobufEnumValueDefinition.kt (70%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/element/ProtobufExtendDefinition.kt (63%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufFieldDefinition.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/element/ProtobufGroupDefinition.kt (65%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMapFieldDefinition.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/element/ProtobufMessageDefinition.kt (75%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/element/ProtobufOneofDefinition.kt (62%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOptionAssign.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/element/ProtobufPackageName.kt (82%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/element/ProtobufRpcDefinition.kt (75%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/element/ProtobufServiceDefinition.kt (63%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFieldAssign.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFileReferenceContributor.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/feature/ProtobufIndexProvider.kt (82%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionHover.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive/stratify => proto/feature}/ProtobufOptionOwner.kt (76%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/feature/ProtobufStubExternalProvider.kt (81%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/feature/ProtobufStubSupport.kt (68%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/impl/ProtobufFileImpl.kt (78%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/impl/ProtobufLineCommentImpl.kt (74%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufEnumValueMixin.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufExtensionFieldNameMixin.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufFieldNameMixin.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/mixin/ProtobufImportStatementMixin.kt (66%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/mixin/ProtobufMessageDefinitionMixin.kt (70%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufOptionNameMixin.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufStringValueMixin.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufTypeNameMixin.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/{ => psi/proto}/reference/ProtobufEnumValueReference.kt (75%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufExtensionFieldReference.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufFieldReference.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/{ => psi/proto}/reference/ProtobufImportReference.kt (92%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufOptionNameReference.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufTypeNameReference.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/structure/ProtobufDefinition.kt (83%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufFieldLike.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/structure/ProtobufMultiNameDefinition.kt (58%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/structure/ProtobufNumberScope.kt (50%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/structure/ProtobufScope.kt (58%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/structure/ProtobufScopeItem.kt (54%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto}/structure/ProtobufScopeItemContainer.kt (50%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufVirtualScope.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/ProtobufStub.kt (85%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{primitive => proto/stub}/StubBasedProtobufElementBase.kt (78%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufEnumStub.kt (54%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufEnumValueStub.kt (52%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufExtendStub.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufFieldStub.kt (52%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufFileStubImpl.kt (71%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufGroupStub.kt (54%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufMapFieldStub.kt (52%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufMessageStub.kt (58%) create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufOneofStub.kt rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufPackageNameStub.kt (52%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufRpcStub.kt (51%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufServiceStub.kt (51%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/impl/ProtobufStubBase.kt (70%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/index/QualifiedNameIndex.kt (75%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/index/ResourceTypeIndex.kt (75%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/index/ShortNameIndex.kt (75%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/primitive/ProtobufNamedStub.kt (94%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufEnumStubType.kt (67%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufEnumValueStubType.kt (68%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufExtendStubType.kt (67%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufFieldStubType.kt (67%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufGroupStubType.kt (67%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufMapFieldStubType.kt (68%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufMessageStubType.kt (70%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufOneofStubType.kt (67%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufPackageNameStubType.kt (68%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufRpcStubType.kt (67%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufServiceStubType.kt (67%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufStubTypeBase.kt (71%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/stub/type/ProtobufStubTypes.kt (96%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/token/ProtobufCommentToken.kt (76%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/token/ProtobufKeywordToken.kt (76%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/token/ProtobufToken.kt (75%) rename src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/{ => proto}/token/ProtobufTokens.kt (95%) delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufExtendStub.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufOneofStub.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextASTFactory.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElement.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementBase.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementType.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextEnumValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFieldName.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFile.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextPsiFactory.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextTypeName.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/feature/ProtoTextFieldAssign.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextFileImpl.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextSharpLineCommentImpl.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextEnumValueMixin.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextFieldNameMixin.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextStringValueMixin.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextTypeNameMixin.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextEnumValueReference.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextFieldReference.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderFileReference.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderMessageReference.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextSharpCommentReferenceContributor.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextTypeNameReference.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextCommentToken.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextKeywordToken.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextToken.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtobufTokens.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/BlockElement.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/FragmentElement.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/StatementElement.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ArrayValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/BooleanValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/EnumValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/IntegerValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/MessageValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/NumberValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/StringValue.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ValueUtils.kt create mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/WrappedValue.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufBuiltInOptionReference.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufFieldReference.kt delete mode 100644 src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufTypeNameReference.kt create mode 100644 src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file.svg create mode 100644 src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file_dark.svg create mode 100644 src/main/resources/io/kanro/idea/plugin/protobuf/icon/protobuf_text_file.svg create mode 100644 src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/cpp_features.proto create mode 100644 src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/java_features.proto diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b5bf3f98..77c251a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,12 +1,12 @@ -# GitHub Actions Workflow created for testing and preparing the plugin release in following steps: -# - validate Gradle Wrapper, -# - run 'test' and 'verifyPlugin' tasks, -# - run Qodana inspections, -# - run 'buildPlugin' task and prepare artifact for the further tests, -# - run 'runPluginVerifier' task, -# - create a draft release. +# GitHub Actions Workflow is created for testing and preparing the plugin release in the following steps: +# - Validate Gradle Wrapper. +# - Run 'test' and 'verifyPlugin' tasks. +# - Run Qodana inspections. +# - Run the 'buildPlugin' task and prepare artifact for further tests. +# - Run the 'runPluginVerifier' task. +# - Create a draft release. # -# Workflow is triggered on push and pull_request events. +# The workflow is triggered on push and pull_request events. # # GitHub Actions reference: https://help.github.com/en/actions # @@ -14,40 +14,49 @@ name: Build on: - # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g. for dependabot pull requests) + # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g., for dependabot pull requests) push: branches: [ main ] # Trigger the workflow on any pull request pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: - # Run Gradle Wrapper Validation Action to verify the wrapper's checksum - # Run verifyPlugin, IntelliJ Plugin Verifier, and test Gradle tasks - # Build plugin and provide the artifact for the next workflow jobs + # Prepare environment and build the plugin build: name: Build runs-on: ubuntu-latest outputs: version: ${{ steps.properties.outputs.version }} changelog: ${{ steps.properties.outputs.changelog }} + pluginVerifierHomeDir: ${{ steps.properties.outputs.pluginVerifierHomeDir }} steps: # Check out current repository - name: Fetch Sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v4 # Validate wrapper - name: Gradle Wrapper Validation - uses: gradle/wrapper-validation-action@v1.0.4 + uses: gradle/actions/wrapper-validation@v3 - # Setup Java 11 environment for the next steps + # Set up Java environment for the next steps - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: zulu java-version: 17 + # Setup Gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + gradle-home-cache-cleanup: true + # Set environment variables - name: Export Properties id: properties @@ -55,86 +64,182 @@ jobs: run: | PROPERTIES="$(./gradlew properties --console=plain -q)" VERSION="$(echo "$PROPERTIES" | grep "^version:" | cut -f2- -d ' ')" - NAME="$(echo "$PROPERTIES" | grep "^pluginName:" | cut -f2- -d ' ')" CHANGELOG="$(./gradlew getChangelog --unreleased --no-header --console=plain -q)" - CHANGELOG="${CHANGELOG//'%'/'%25'}" - CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" - CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" - echo "::set-output name=version::$VERSION" - echo "::set-output name=name::$NAME" - echo "::set-output name=changelog::$CHANGELOG" - echo "::set-output name=pluginVerifierHomeDir::~/.pluginVerifier" + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "pluginVerifierHomeDir=~/.pluginVerifier" >> $GITHUB_OUTPUT + + echo "changelog<> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT ./gradlew listProductsReleases # prepare list of IDEs for Plugin Verifier + # Build plugin + - name: Build plugin + run: ./gradlew buildPlugin + + # Prepare plugin archive content for creating artifact + - name: Prepare Plugin Artifact + id: artifact + shell: bash + run: | + cd ${{ github.workspace }}/build/distributions + FILENAME=`ls *.zip` + unzip "$FILENAME" -d content + + echo "filename=${FILENAME:0:-4}" >> $GITHUB_OUTPUT + + # Store already-built plugin as an artifact for downloading + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.artifact.outputs.filename }} + path: ./build/distributions/content/*/* + + # Run tests and upload a code coverage report + test: + name: Test + needs: [ build ] + runs-on: ubuntu-latest + steps: + + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v4 + + # Set up Java environment for the next steps + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: zulu + java-version: 17 + + # Setup Gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + gradle-home-cache-cleanup: true + # Run tests - name: Run Tests - run: ./gradlew test + run: ./gradlew check # Collect Tests Result of failed tests - name: Collect Tests Result if: ${{ failure() }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: tests-result path: ${{ github.workspace }}/build/reports/tests + # Upload the Kover report to CodeCov + - name: Upload Code Coverage Report + uses: codecov/codecov-action@v4 + with: + files: ${{ github.workspace }}/build/reports/kover/report.xml + + # Run Qodana inspections and provide report + inspectCode: + name: Inspect code + needs: [ build ] + runs-on: ubuntu-latest + permissions: + contents: write + checks: write + pull-requests: write + steps: + + # Free GitHub Actions Environment Disk Space + - name: Maximize Build Space + uses: jlumbroso/free-disk-space@main + with: + tool-cache: false + large-packages: false + + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v4 + + # Set up Java environment for the next steps + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: zulu + java-version: 17 + + # Run Qodana inspections + - name: Qodana - Code Inspection + uses: JetBrains/qodana-action@v2024.1.5 + with: + cache-default-branch-only: true + + # Run plugin structure verification along with IntelliJ Plugin Verifier + verify: + name: Verify plugin + needs: [ build ] + runs-on: ubuntu-latest + steps: + + # Free GitHub Actions Environment Disk Space + - name: Maximize Build Space + uses: jlumbroso/free-disk-space@main + with: + tool-cache: false + large-packages: false + + # Check out current repository + - name: Fetch Sources + uses: actions/checkout@v4 + + # Set up Java environment for the next steps + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: zulu + java-version: 17 + + # Setup Gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + gradle-home-cache-cleanup: true + # Cache Plugin Verifier IDEs - name: Setup Plugin Verifier IDEs Cache - uses: actions/cache@v2.1.7 + uses: actions/cache@v4 with: - path: ${{ steps.properties.outputs.pluginVerifierHomeDir }}/ides + path: ${{ needs.build.outputs.pluginVerifierHomeDir }}/ides key: plugin-verifier-${{ hashFiles('build/listProductsReleases.txt') }} # Run Verify Plugin task and IntelliJ Plugin Verifier tool - name: Run Plugin Verification tasks - run: ./gradlew runPluginVerifier -Pplugin.verifier.home.dir=${{ steps.properties.outputs.pluginVerifierHomeDir }} + run: ./gradlew runPluginVerifier -Dplugin.verifier.home.dir=${{ needs.build.outputs.pluginVerifierHomeDir }} # Collect Plugin Verifier Result - name: Collect Plugin Verifier Result if: ${{ always() }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: pluginVerifier-result path: ${{ github.workspace }}/build/reports/pluginVerifier - # # Run Qodana inspections - # - name: Qodana - Code Inspection - # uses: JetBrains/qodana-action@v2022.2.4 - - # Prepare plugin archive content for creating artifact - - name: Prepare Plugin Artifact - id: artifact - shell: bash - run: | - cd ${{ github.workspace }}/build/distributions - FILENAME=`ls *.zip` - unzip "$FILENAME" -d content - - echo "::set-output name=filename::${FILENAME:0:-4}" - - # Store already-built plugin as an artifact for downloading - - name: Upload artifact - uses: actions/upload-artifact@v2.2.4 - with: - name: ${{ steps.artifact.outputs.filename }} - path: ./build/distributions/content/*/* - # Prepare a draft release for GitHub Releases page for the manual verification # If accepted and published, release workflow would be triggered releaseDraft: - name: Release Draft + name: Release draft if: github.event_name != 'pull_request' - needs: build + needs: [ build, test, inspectCode, verify ] runs-on: ubuntu-latest + permissions: + contents: write steps: # Check out current repository - name: Fetch Sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v4 - # Remove old release drafts by using the curl request for the available releases with draft flag + # Remove old release drafts by using the curl request for the available releases with a draft flag - name: Remove Old Release Drafts env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -143,12 +248,12 @@ jobs: --jq '.[] | select(.draft == true) | .id' \ | xargs -I '{}' gh api -X DELETE repos/{owner}/{repo}/releases/{} - # Create new release draft - which is not publicly visible and requires manual acceptance + # Create a new release draft which is not publicly visible and requires manual acceptance - name: Create Release Draft env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - gh release create v${{ needs.build.outputs.version }} \ + gh release create "v${{ needs.build.outputs.version }}" \ --draft \ --title "v${{ needs.build.outputs.version }}" \ --notes "$(cat << 'EOM' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 81e2cf26..48987791 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,32 +1,42 @@ -# GitHub Actions Workflow created for handling the release process based on the draft release prepared -# with the Build workflow. Running the publishPlugin task requires the PUBLISH_TOKEN secret provided. +# GitHub Actions Workflow created for handling the release process based on the draft release prepared with the Build workflow. +# Running the publishPlugin task requires all following secrets to be provided: PUBLISH_TOKEN, PRIVATE_KEY, PRIVATE_KEY_PASSWORD, CERTIFICATE_CHAIN. +# See https://plugins.jetbrains.com/docs/intellij/plugin-signing.html for more information. name: Release on: release: - types: [ prereleased, released ] + types: [prereleased, released] jobs: - # Prepare and publish the plugin to the Marketplace repository + # Prepare and publish the plugin to JetBrains Marketplace repository release: name: Publish Plugin runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write steps: # Check out current repository - name: Fetch Sources - uses: actions/checkout@v2.4.0 + uses: actions/checkout@v4 with: ref: ${{ github.event.release.tag_name }} - # Setup Java 11 environment for the next steps + # Set up Java environment for the next steps - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: zulu java-version: 17 + # Setup Gradle + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + gradle-home-cache-cleanup: true + # Set environment variables - name: Export Properties id: properties @@ -37,11 +47,9 @@ jobs: EOM )" - CHANGELOG="${CHANGELOG//'%'/'%25'}" - CHANGELOG="${CHANGELOG//$'\n'/'%0A'}" - CHANGELOG="${CHANGELOG//$'\r'/'%0D'}" - - echo "::set-output name=changelog::$CHANGELOG" + echo "changelog<> $GITHUB_OUTPUT + echo "$CHANGELOG" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT # Update Unreleased section with the current release note - name: Patch Changelog @@ -51,10 +59,13 @@ jobs: run: | ./gradlew patchChangelog --release-note="$CHANGELOG" - # Publish the plugin to the Marketplace + # Publish the plugin to JetBrains Marketplace - name: Publish Plugin env: PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} + CERTIFICATE_CHAIN: ${{ secrets.CERTIFICATE_CHAIN }} + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + PRIVATE_KEY_PASSWORD: ${{ secrets.PRIVATE_KEY_PASSWORD }} run: ./gradlew publishPlugin # Upload artifact as a release asset @@ -63,7 +74,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/* - # Create pull request + # Create a pull request - name: Create Pull Request if: ${{ steps.properties.outputs.changelog != '' }} env: @@ -71,6 +82,7 @@ jobs: run: | VERSION="${{ github.event.release.tag_name }}" BRANCH="changelog-update-$VERSION" + LABEL="release changelog" git config user.email "action@github.com" git config user.name "GitHub Action" @@ -78,9 +90,14 @@ jobs: git checkout -b $BRANCH git commit -am "Changelog update - $VERSION" git push --set-upstream origin $BRANCH + + gh label create "$LABEL" \ + --description "Pull requests with release changelog update" \ + --force \ + || true gh pr create \ --title "Changelog update - \`$VERSION\`" \ --body "Current pull request contains patched \`CHANGELOG.md\` file for the \`$VERSION\` version." \ - --base main \ - --head $BRANCH + --label "$LABEL" \ + --head $BRANCH \ No newline at end of file diff --git a/.run/Run IDE with Plugin.run.xml b/.run/Run IDE with Plugin.run.xml index ddd22adf..6d21d8a4 100644 --- a/.run/Run IDE with Plugin.run.xml +++ b/.run/Run IDE with Plugin.run.xml @@ -1,25 +1,25 @@ - - - - - - - true - true - false - false - - + + + + + + + true + true + false + false + + \ No newline at end of file diff --git a/.run/Run Plugin.run.xml b/.run/Run Plugin.run.xml new file mode 100644 index 00000000..02cf47e2 --- /dev/null +++ b/.run/Run Plugin.run.xml @@ -0,0 +1,30 @@ + + + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/Run Tests.run.xml b/.run/Run Tests.run.xml index bbf1f0a3..009fc459 100644 --- a/.run/Run Tests.run.xml +++ b/.run/Run Tests.run.xml @@ -1,30 +1,30 @@ - - - - - - - - true - true - false - false - - + + + + + + + + true + true + false + false + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2806aafe..9cf64514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,17 +15,28 @@ ## 1.7.30 - 2023-12-08 - Changelog update - `v1.7.20` by @github-actions in https://github.com/devkanro/intellij-protobuf-plugin/pull/203 -- ⬆️ Bump org.jetbrains.intellij from 1.13.3 to 1.16.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/206 -- ⬆️ Bump org.jetbrains.grammarkit from 2022.3.1 to 2022.3.2 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/205 -- ⬆️ Bump org.jetbrains.changelog from 2.0.0 to 2.2.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/204 -- ⬆️ Bump org.jmailen.kotlinter from 4.0.1 to 4.1.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/207 -- ⬆️ Bump com.fasterxml.jackson.dataformat:jackson-dataformat-yaml from 2.15.3 to 2.16.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/208 -- ⬆️ Bump org.jetbrains.kotlin.jvm from 1.9.20 to 1.9.21 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/209 -- ⬆️ Bump com.bybutter.sisyphus:sisyphus-jackson-protobuf from 2.1.20 to 2.1.21 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/211 -- ⬆️ Bump io.grpc:grpc-netty from 1.59.0 to 1.59.1 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/212 -- ⬆️ Bump com.bybutter.sisyphus:sisyphus-grpc from 2.1.20 to 2.1.21 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/210 -- ⬆️ Bump org.jetbrains.intellij from 1.16.0 to 1.16.1 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/213 -- ⬆️ Bump io.grpc:grpc-netty from 1.59.1 to 1.60.0 by @dependabot in https://github.com/devkanro/intellij-protobuf-plugin/pull/215 +- ⬆️ Bump org.jetbrains.intellij from 1.13.3 to 1.16.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/206 +- ⬆️ Bump org.jetbrains.grammarkit from 2022.3.1 to 2022.3.2 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/205 +- ⬆️ Bump org.jetbrains.changelog from 2.0.0 to 2.2.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/204 +- ⬆️ Bump org.jmailen.kotlinter from 4.0.1 to 4.1.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/207 +- ⬆️ Bump com.fasterxml.jackson.dataformat:jackson-dataformat-yaml from 2.15.3 to 2.16.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/208 +- ⬆️ Bump org.jetbrains.kotlin.jvm from 1.9.20 to 1.9.21 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/209 +- ⬆️ Bump com.bybutter.sisyphus:sisyphus-jackson-protobuf from 2.1.20 to 2.1.21 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/211 +- ⬆️ Bump io.grpc:grpc-netty from 1.59.0 to 1.59.1 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/212 +- ⬆️ Bump com.bybutter.sisyphus:sisyphus-grpc from 2.1.20 to 2.1.21 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/210 +- ⬆️ Bump org.jetbrains.intellij from 1.16.0 to 1.16.1 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/213 +- ⬆️ Bump io.grpc:grpc-netty from 1.59.1 to 1.60.0 by @dependabot + in https://github.com/devkanro/intellij-protobuf-plugin/pull/215 ## 1.7.20 - 2023-11-13 diff --git a/README.md b/README.md index 25653adb..a1081c72 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,10 @@ Analyzing features: ✅ Decompile from proto descriptor for golang ✅ Send gRPC native/transcoding requests via [Http Client](https://plugins.jetbrains.com/plugin/13121-http-client) ✅ Explore gRPC APIs via [Endpoints](https://plugins.jetbrains.com/plugin/16890-endpoints) -✅ [Buf](https://buf.build/) support via [Buf for Protocol Buffers](https://plugins.jetbrains.com/plugin/19147-buf-for-protocol-buffers) +✅ [Buf](https://buf.build/) support +via [Buf for Protocol Buffers](https://plugins.jetbrains.com/plugin/19147-buf-for-protocol-buffers) +✅ [Protobuf Editions](https://protobuf.dev/editions/overview/) support +✅ [Protobuf Text Format](https://protobuf.dev/reference/protobuf/textformat-spec/) support Editor features: @@ -49,10 +52,6 @@ Editor features: -Planned features: - -🙋 Proto text support - ## Screenshots ![screenshot](resources/screenshot.png) diff --git a/build.gradle.kts b/build.gradle.kts index 5ae34070..b16ede86 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,30 +1,27 @@ import org.jetbrains.changelog.Changelog import org.jetbrains.changelog.markdownToHTML +import org.jetbrains.grammarkit.tasks.GenerateLexerTask +import org.jetbrains.grammarkit.tasks.GenerateParserTask import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile -fun properties(key: String) = project.findProperty(key).toString() +fun properties(key: String) = providers.gradleProperty(key) + +fun environment(key: String) = providers.environmentVariable(key) plugins { - // Java support - id("java") - // Kotlin support - id("org.jetbrains.kotlin.jvm") version "1.9.22" - // Gradle IntelliJ Plugin - id("org.jetbrains.intellij") version "1.17.2" - // Gradle Changelog Plugin - id("org.jetbrains.changelog") version "2.2.0" - // Gradle Qodana Plugin - id("org.jetbrains.qodana") version "0.1.13" - - id("org.jetbrains.grammarkit") version "2022.3.2.2" - - id("org.jmailen.kotlinter") version "4.3.0" + id("java") // Java support + alias(libs.plugins.kotlin) // Kotlin support + alias(libs.plugins.gradleIntelliJPlugin) // Gradle IntelliJ Plugin + alias(libs.plugins.changelog) // Gradle Changelog Plugin + alias(libs.plugins.qodana) // Gradle Qodana Plugin + alias(libs.plugins.kover) // Gradle Kover Plugin + alias(libs.plugins.grammarkit) // IntelliJ Grammark kit Plugin } -group = properties("pluginGroup") -version = properties("pluginVersion") +group = properties("pluginGroup").get() +version = properties("pluginVersion").get() +// Configure project's dependencies repositories { mavenLocal() mavenCentral() @@ -39,94 +36,126 @@ dependencies { implementation("io.grpc:grpc-netty:1.62.2") } -// Configure gradle-intellij-plugin plugin. -// Read more: https://github.com/JetBrains/gradle-intellij-plugin +// Set the JVM language level used to build the project. +kotlin { + jvmToolchain(17) + compilerOptions { + freeCompilerArgs.add("-Xjvm-default=all") + } +} + +// Configure Gradle IntelliJ Plugin - read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html intellij { - pluginName.set(properties("pluginName")) - version.set(properties("platformVersion")) - type.set(properties("platformType")) + pluginName = properties("pluginName") + version = properties("platformVersion") + type = properties("platformType") // Plugin Dependencies. Uses `platformPlugins` property from the gradle.properties file. - plugins.set(properties("platformPlugins").split(',').map(String::trim).filter(String::isNotEmpty)) + plugins = properties("platformPlugins").map { it.split(',').map(String::trim).filter(String::isNotEmpty) } } +// Configure Gradle Changelog Plugin - read more: https://github.com/JetBrains/gradle-changelog-plugin changelog { - version.set(properties("pluginVersion")) - groups.set(emptyList()) -} - -qodana { - cachePath.set(projectDir.resolve(".qodana").canonicalPath) - reportPath.set(projectDir.resolve("build/reports/inspections").canonicalPath) - saveReport.set(true) - showReport.set(System.getenv("QODANA_SHOW_REPORT")?.toBoolean() ?: false) + groups.empty() + repositoryUrl = properties("pluginRepositoryUrl") } -tasks { - properties("javaVersion").let { - withType { - sourceCompatibility = it - targetCompatibility = it - } - withType { - kotlinOptions.jvmTarget = it - kotlinOptions.freeCompilerArgs += "-Xjvm-default=all" - dependsOn(named("generateLexer"), named("generateParser")) +// Configure Gradle Kover Plugin - read more: https://github.com/Kotlin/kotlinx-kover#configuration +kover { + reports { + total { + xml { + onCheck = true + } } } +} +tasks { wrapper { - gradleVersion = properties("gradleVersion") + gradleVersion = properties("gradleVersion").get() } patchPluginXml { - version.set(properties("pluginVersion")) - sinceBuild.set(properties("pluginSinceBuild")) - untilBuild.set(properties("pluginUntilBuild")) + version = properties("pluginVersion") + sinceBuild = properties("pluginSinceBuild") + untilBuild = properties("pluginUntilBuild") // Extract the section from README.md and provide for the plugin's manifest - pluginDescription.set( - projectDir.resolve("README.md").readText().lines().run { + pluginDescription = + providers.fileContents(layout.projectDirectory.file("README.md")).asText.map { val start = "" val end = "" - if (!containsAll(listOf(start, end))) { - throw GradleException("Plugin description section not found in README.md:\n$start ... $end") + with(it.lines()) { + if (!containsAll(listOf(start, end))) { + throw GradleException("Plugin description section not found in README.md:\n$start ... $end") + } + subList(indexOf(start) + 1, indexOf(end)).joinToString("\n").let(::markdownToHTML) } - subList(indexOf(start) + 1, indexOf(end)) - }.joinToString("\n").run { markdownToHTML(this) }, - ) + } + val changelog = project.changelog // local variable for configuration cache compatibility // Get the latest available change notes from the changelog file - changeNotes.set( - provider { - changelog.renderItem( - changelog.run { - getOrNull(properties("pluginVersion")) ?: getLatest() - }, - Changelog.OutputType.HTML, - ) - }, - ) + changeNotes = + properties("pluginVersion").map { pluginVersion -> + with(changelog) { + renderItem( + (getOrNull(pluginVersion) ?: getUnreleased()) + .withHeader(false) + .withEmptySections(false), + Changelog.OutputType.HTML, + ) + } + } + } + + // Configure UI tests plugin + // Read more: https://github.com/JetBrains/intellij-ui-test-robot + runIdeForUiTests { + systemProperty("robot-server.port", "8082") + systemProperty("ide.mac.message.dialogs.as.sheets", "false") + systemProperty("jb.privacy.policy.text", "") + systemProperty("jb.consents.confirmation.enabled", "false") + } + + runIde { + jvmArguments.add("-Didea.ProcessCanceledException=disabled") } generateLexer { - sourceFile.set(projectDir.resolve("src/main/grammar/protobuf.flex")) - targetOutputDir.set(buildDir.resolve("generated/sources/grammar/io/kanro/idea/plugin/protobuf/lang/lexer")) - purgeOldFiles.set(true) + sourceFile = layout.projectDirectory.file("src/main/grammar/protobuf.flex") + targetOutputDir = + layout.buildDirectory.dir("generated/sources/grammar/io/kanro/idea/plugin/protobuf/lang/lexer/proto") + purgeOldFiles = true } generateParser { - sourceFile.set(projectDir.resolve("src/main/grammar/protobuf.bnf")) - targetRootOutputDir.set(buildDir.resolve("generated/sources/grammar")) - purgeOldFiles.set(true) - pathToParser.set("io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParser.java") - pathToPsiRoot.set("io/kanro/idea/plugin/protobuf/lang/psi") + sourceFile = layout.projectDirectory.file("src/main/grammar/protobuf.bnf") + targetRootOutputDir = layout.buildDirectory.dir("generated/sources/grammar") + purgeOldFiles = true + pathToParser = "io/kanro/idea/plugin/protobuf/lang/psi/proto/parser/ProtobufParser.java" + pathToPsiRoot = "io/kanro/idea/plugin/protobuf/lang/psi/proto" + } + + create("generateTextParser") { + sourceFile = layout.projectDirectory.file("src/main/grammar/prototext.bnf") + targetRootOutputDir = layout.buildDirectory.dir("generated/sources/grammar") + purgeOldFiles = true + pathToParser = "io/kanro/idea/plugin/protobuf/lang/psi/text/parser/ProtoTextParser.java" + pathToPsiRoot = "io/kanro/idea/plugin/protobuf/lang/psi/text" + } + + create("generateTextLexer") { + sourceFile = layout.projectDirectory.file("src/main/grammar/prototext.flex") + targetOutputDir = + layout.buildDirectory.dir("generated/sources/grammar/io/kanro/idea/plugin/protobuf/lang/lexer/text") + purgeOldFiles = true } prepareSandbox { + val file = layout.buildDirectory.file("idea-sandbox/config/disabled_plugins.txt").get().asFile doLast { - val file = file(buildDir.resolve("idea-sandbox/config/disabled_plugins.txt")) file.ensureParentDirsCreated() file.writeText( buildString { @@ -139,18 +168,27 @@ tasks { publishPlugin { dependsOn("patchChangelog") - token.set(System.getenv("PUBLISH_TOKEN")) + token = environment("PUBLISH_TOKEN") // pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3 // Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more: // https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel - channels.set(listOf(properties("pluginVersion").split('-').getOrElse(1) { "default" }.split('.').first())) + channels = + properties("pluginVersion").map { + listOf( + it.substringAfter('-', "").substringBefore('.').ifEmpty { "default" }, + ) + } + } + + compileKotlin { + dependsOn(generateParser, named("generateTextParser"), generateLexer, named("generateTextLexer")) } } sourceSets { named("main") { java { - srcDir(buildDir.resolve("generated/sources/grammar")) + srcDir(layout.buildDirectory.dir("generated/sources/grammar")) } } } diff --git a/gradle.properties b/gradle.properties index 66a5ceeb..e75c65b1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,26 +1,24 @@ -# IntelliJ Platform Artifacts Repositories -# -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html +# IntelliJ Platform Artifacts Repositories -> https://plugins.jetbrains.com/docs/intellij/intellij-artifacts.html pluginGroup=io.kanro.idea.plugin.protobuf pluginName=IntelliJ Protobuf Language Plugin +pluginRepositoryUrl=https://github.com/devkanro/intellij-protobuf-plugin # SemVer format -> https://semver.org -pluginVersion=1.7.60 -# See https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html -# for insight into build numbers and IntelliJ Platform versions. +pluginVersion=2.0.0 +# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html pluginSinceBuild=241 -pluginUntilBuild=241.* -# IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties +pluginUntilBuild=242.* +# IntelliJ Platform Properties -> https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension platformType=IU -#platformVersion=241.14024-EAP-CANDIDATE-SNAPSHOT platformVersion=2024.1 # Plugin Dependencies -> https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html # Example: platformPlugins = com.intellij.java, com.jetbrains.php:203.4449.22 platformPlugins=com.intellij.java, org.jetbrains.kotlin, org.intellij.plugins.markdown, org.jetbrains.plugins.go:241.14494.240, com.jetbrains.restClient:241.14494.150, com.intellij.grpc:241.14494.150 -#platformPlugins=com.intellij.java, org.jetbrains.kotlin, org.jetbrains.plugins.yaml, org.intellij.plugins.markdown, org.jetbrains.plugins.go:232.8660.142, com.jetbrains.restClient:232.8660.88, com.intellij.grpc:232.8660.88 -# Java language level used to compile sources and to generate the files for - Java 11 is required since 2020.3 -javaVersion=17 # Gradle Releases -> https://github.com/gradle/gradle/releases -gradleVersion=8.0.2 -# Opt-out flag for bundling Kotlin standard library. -# See https://plugins.jetbrains.com/docs/intellij/kotlin.html#kotlin-standard-library for details. -# suppress inspection "UnusedProperty" +gradleVersion=8.7 +# Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib kotlin.stdlib.default.dependency=false +# Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html +org.gradle.configuration-cache=true +# Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html +org.gradle.caching=true +kotlin.daemon.jvmargs=-Xmx16G \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..a6640f78 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,22 @@ +[versions] +# libraries +exampleLibrary = "24.1.0" + +# plugins +kotlin = "2.0.0" +changelog = "2.2.0" +gradleIntelliJPlugin = "1.17.3" +qodana = "2024.1.5" +kover = "0.8.0" +grammarkit = "2022.3.2.2" + +[libraries] +exampleLibrary = { group = "com.example", name = "exampleLibrary", version.ref = "exampleLibrary" } + +[plugins] +changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" } +gradleIntelliJPlugin = { id = "org.jetbrains.intellij", version.ref = "gradleIntelliJPlugin" } +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } +qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" } +grammarkit = { id = "org.jetbrains.grammarkit", version.ref = "grammarkit" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..ccebba7710deaf9f98673a68957ea02138b60d0a 100644 GIT binary patch delta 42019 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 delta 39521 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 R149saZvb8 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,105 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 107acd32..93e3f59f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/qodana.yml b/qodana.yml index 8b73731b..0be93537 100644 --- a/qodana.yml +++ b/qodana.yml @@ -2,5 +2,11 @@ # https://www.jetbrains.com/help/qodana/qodana-yaml.html version: 1.0 +linter: jetbrains/qodana-jvm-community:latest +projectJDK: "17" profile: - name: qodana.recommended \ No newline at end of file + name: qodana.recommended +exclude: + - name: All + paths: + - .qodana \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 172ab2ab..7ad66d90 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1,5 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" +} + rootProject.name = "idea-protobuf-plugin" diff --git a/src/main/grammar/protobuf.bnf b/src/main/grammar/protobuf.bnf index eb485918..0ec8dcd8 100644 --- a/src/main/grammar/protobuf.bnf +++ b/src/main/grammar/protobuf.bnf @@ -1,20 +1,20 @@ { generate=[names="long" psi="yes" tokens="no"] - parserClass="io.kanro.idea.plugin.protobuf.lang.parser.ProtobufParser" + parserClass="io.kanro.idea.plugin.protobuf.lang.psi.proto.parser.ProtobufParser" parserUtilClass="io.kanro.idea.plugin.protobuf.lang.parser.ProtobufParserUtil" parserImports=[ - "static io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens.*" + "static io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens.*" ] psiClassPrefix="Protobuf" psiImplClassSuffix="Impl" - psiPackage="io.kanro.idea.plugin.protobuf.lang.psi" - psiImplPackage="io.kanro.idea.plugin.protobuf.lang.psi.impl" + psiPackage="io.kanro.idea.plugin.protobuf.lang.psi.proto" + psiImplPackage="io.kanro.idea.plugin.protobuf.lang.psi.proto.impl" - implements="io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement" - extends="io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase" + implements="io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + extends="io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase" - elementTypeHolderClass="io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypes" - elementTypeClass="io.kanro.idea.plugin.protobuf.lang.psi.ProtobufElementType" + elementTypeHolderClass="io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypes" + elementTypeClass="io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementType" tokens = [ SKIPPED_WHITESPACE = "regexp:[ \n\t\r\f]+" @@ -38,16 +38,19 @@ LPAREN = '(' LT = '<' MINUS = '-' + PLUS = '+' RBRACE = '}' RBRACK = ']' RPAREN = ')' SEMI = ';' + SLASH = '/' + COLON = ':' SYMBOL = "regexp:[!#$%&()*+,-./:;<=>?@\[\\\]^`{|}~]" ] } -File ::= SyntaxStatement? FileElement* +File ::= (EditionStatement | SyntaxStatement)? FileElement* private FileElement ::= ImportStatement | PackageStatement | FileOption | TopLevelDefinition | ExtendDefinition | ';' { recoverWhile = FileElementRecovery @@ -57,36 +60,63 @@ private FileElementRecovery ::= !(message | enum | service | extend | import | p private TopLevelDefinition ::= MessageDefinition | EnumDefinition | ServiceDefinition /* File statements */ +EditionStatement ::= edition '=' StringValue ';' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] +} + SyntaxStatement ::= syntax '=' StringValue ';' { pin=1 - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] } + PackageStatement ::= package PackageName ('.' PackageName)* ';' { pin=1 - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] } + PackageName::= IdentifierWithKeyword { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufPackageName" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufPackageName" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufPackageNameMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufPackageNameStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufPackageNameMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufPackageNameStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + ImportStatement ::= import ImportLabel? StringValue ';' { pin=1 - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement"] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufImportStatementMixin" + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufImportStatementMixin" } + ImportLabel ::= public | weak { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] } + FileOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } @@ -94,45 +124,50 @@ FileOption ::= option OptionAssign ';' { OptionAssign ::= OptionName '=' Constant { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufOptionAssign" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufOptionAssign" ] recoverWhile=OptionAssignRecovery } + private OptionAssignRecovery ::= !(option | ',' | '}' | ']' | ';') -OptionName ::= (BuiltInOptionName | ExtensionOptionName) ('.' FieldName)* { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] -} -BuiltInOptionName ::= IdentifierWithKeyword { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufBuiltInOptionMixin" -} -ExtensionOptionName ::= '(' TypeName ')' { - pin=1 - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] +OptionName ::= OptionFieldName ('.' OptionName)? { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.QualifiedElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufOptionNameMixin" } +private OptionFieldName ::= SymbolName | '(' ExtensionFieldName ')' + /* Message */ MessageDefinition ::= message Identifier MessageBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufMessageDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufMessageDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufMessageDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufMessageDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + MessageBody ::= '{' MessageElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + private MessageElement ::= MessageDefinition | EnumDefinition @@ -151,8 +186,9 @@ private MessageElementRecovery ::= !(message | enum | extensions | reserved | ex MessageOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } @@ -160,26 +196,31 @@ MessageOption ::= option OptionAssign ';' { FieldDefinition ::= FieldLabel? TypeName Identifier '=' IntegerValue FieldOptionBlock? ';' { pin=2 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufFieldDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufFieldDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufFieldDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufFieldStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufFieldDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufFieldStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + FieldOptionBlock ::= '[' FieldOption (',' FieldOption)* ']' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + FieldOption ::= OptionAssign { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] recoverWhile=OptionBlockRecovery } @@ -187,109 +228,157 @@ FieldOption ::= OptionAssign { private OptionBlockRecovery ::= !(',' | ']') FieldLabel ::= required | optional | repeated { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] } OneofDefinition ::= oneof Identifier OneofBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufOneofDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufOneofDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufOneofDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufOneofStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufOneofDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufOneofStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + OneofBody ::= '{' OneofElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + private OneofElement ::= OneofOption | GroupDefinition | FieldDefinition | ';' {recoverWhile=OneofElementRecovery} private OneofElementRecovery ::= !(FieldLabel | option | group | TypeName | ';' | '}') OneofOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } MapFieldDefinition ::= map '<' TypeName ',' TypeName '>' Identifier '=' IntegerValue FieldOptionBlock? ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufMapFieldDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufMapFieldDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufMapFieldDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMapFieldStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufMapFieldDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMapFieldStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } GroupDefinition ::= FieldLabel? group Identifier '=' IntegerValue MessageBody { pin=2 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufGroupDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufGroupDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufGroupDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufGroupStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufGroupDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufGroupStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } -ExtensionStatement ::= extensions Ranges ';' { +ExtensionStatement ::= extensions ExtensionRanges ';' { pin = 1; implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + ] +} + +private ExtensionRanges ::= ExtensionRange (',' ExtensionRange)* + +ExtensionRange ::= IntegerValue (to (IntegerValue | max))? ExtensionRangeOptionBlock? { + recoverWhile=RangeRecovery + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" + ] +} + +ExtensionRangeOptionBlock ::= '[' ExtensionRangeOption (',' ExtensionRangeOption)* ']' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + ] +} +ExtensionRangeOption ::= OptionAssign { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] + recoverWhile=OptionBlockRecovery } ReservedStatement ::= reserved ReservedElement ';'{ pin = 1; implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" ] } -private ReservedElement ::= Ranges | FieldNames -private Ranges ::= ReservedRange (',' ReservedRange)* + +private ReservedElement ::= ReservedRanges | ReservedFieldNames +private ReservedRanges ::= ReservedRange (',' ReservedRange)* ReservedRange ::= IntegerValue (to (IntegerValue | max))? { recoverWhile=RangeRecovery implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" ] } + private RangeRecovery ::= !(IntegerValue | ',' | '[' | ';') MessageElementRecovery -private FieldNames ::= ReservedName (',' ReservedName)* -ReservedName ::= IdentifierWithKeyword { +private ReservedFieldNames ::= ReservedName (',' ReservedName)* +ReservedName ::= STRING_LITERAL | IdentifierWithKeyword { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" ] } EnumDefinition ::= enum Identifier EnumBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufEnumDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufEnumDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufEnumDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufEnumDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } EnumBody ::= '{' EnumElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } private EnumElement ::= EnumOption | ReservedStatement | EnumValueDefinition | ';' {recoverWhile=EnumElementRecovery} @@ -297,33 +386,40 @@ private EnumElementRecovery ::= !(option | reserved | EnumValueDefinition | ';' EnumOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } + EnumValueDefinition ::= Identifier '=' IntegerValue EnumValueOptionBlock? ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufEnumValueDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufEnumValueDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufEnumValueDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufEnumValueDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + EnumValueOptionBlock ::= '[' EnumValueOption (',' EnumValueOption)* ']' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + EnumValueOption ::= OptionAssign { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] recoverWhile=OptionBlockRecovery } @@ -331,153 +427,273 @@ EnumValueOption ::= OptionAssign { ServiceDefinition ::= service Identifier ServiceBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufServiceDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufServiceDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufServiceDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufServiceDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } ServiceBody ::= '{' ServiceElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + private ServiceElement ::= ServiceOption | RpcDefinition | ';' {recoverWhile=ServiceElementRecovery} private ServiceElementRecovery ::= !(option | stream | rpc | ';' | '}') ServiceOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } RpcDefinition ::= rpc Identifier RpcIO returns RpcIO ( RpcBody | ';') { pin = 1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufRpcDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufRpcDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufRpcDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufRpcDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } + RpcIO ::= '(' stream? TypeName ')' { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + ] } + RpcBody ::= '{' RpcElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } + private RpcElement ::= RpcOption | ';' { recoverWhile=RpcElementRecovery } private RpcElementRecovery ::= !(option | ';' | '}') RpcOption ::= option OptionAssign ';' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover" ] } ExtendDefinition ::= extend TypeName ExtendBody { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufExtendDefinition" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufExtendDefinition" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufExtendDefinitionMixin" - stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufExtendStub" - elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes.get' + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufExtendDefinitionMixin" + stubClass= "io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufExtendStub" + elementTypeFactory = 'io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes.get' } ExtendBody ::= '{' ExtendElement* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" ] } private ExtendElement ::= GroupDefinition | FieldDefinition | ';' {recoverWhile=ExtendElementRecovery} private ExtendElementRecovery ::= !(FieldLabel | group | TypeName | ';' | '}') -Constant ::= (StringValue+) | NumberValue | BooleanValue | MessageValue | EnumValue | ArrayValue { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement"] -} -TypeName ::= '.'? SymbolName ('.' SymbolName)* { +TypeName ::= '.'? SymbolName ('.' TypeName)? { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFileReferenceContributor" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.QualifiedElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFileReferenceContributor" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufTypeNameMixin" -} -SymbolName ::= IdentifierWithKeyword { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufTypeNameMixin" } -FieldName ::= IdentifierWithKeyword { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufFieldNameMixin" + +ExtensionFieldName ::= '.'? SymbolName ('.' ExtensionFieldName)? { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.QualifiedElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFileReferenceContributor" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufExtensionFieldNameMixin" } -EnumValue ::= IdentifierWithKeyword { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufEnumValueMixin" + +SymbolName::= IdentifierWithKeyword { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] } + Identifier::= IdentifierWithKeyword { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" ] } private IdentifierWithKeyword ::= IDENTIFIER_LITERAL | <> -StringValue ::= STRING_LITERAL { +StringValue ::= STRING_LITERAL+ { implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFileReferenceContributor" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFileReferenceContributor" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.ReferenceElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.StringValue" ] - mixin="io.kanro.idea.plugin.protobuf.lang.psi.mixin.ProtobufStringValueMixin" + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufStringValueMixin" } -IntegerValue ::= '-'? INTEGER_LITERAL{ - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + +IntegerValue ::= ('-' | '+')? INTEGER_LITERAL{ + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.IntegerValue" + ] } -NumberValue ::= '-'? (INTEGER_LITERAL | FLOAT_LITERAL | 'inf' | 'nan'){ - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + +NumberValue ::= ('-' | '+')? (INTEGER_LITERAL | FLOAT_LITERAL | 'inf' | 'nan') { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.NumberValue" + ] } + + BooleanValue ::= (false | true) { - implements=["io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufFragment"] + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.BooleanValue" + ] +} + +EnumValue ::= IdentifierWithKeyword { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.EnumValue" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufEnumValueMixin" +} + +Constant ::= StringValue | BooleanValue | NumberValue | MessageValue | EnumValue { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.WrappedValue" + ] +} + +FieldName ::= SymbolName | ExtensionName | AnyName { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin.ProtobufFieldNameMixin" } -MessageValue ::= '{' FieldAssign* '}' { + +Domain ::= Identifier ( '.' Identifier )* { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + + +ExtensionName ::= '[' ExtensionFieldName ']' { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +AnyName ::= '[' Domain '/' TypeName ']' { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + + +ScalarList ::= '[' ScalarValue (',' ScalarValue)* ']' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue" ] } -ArrayValue ::= '[' Constant (',' Constant)* ']' { + +ScalarValue ::= StringValue | NumberValue | BooleanValue | EnumValue { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.WrappedValue" + ] +} + +MessageValue ::= '{' Field* '}' { pin=1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBody" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue" ] } -FieldAssign ::= FieldName ':' Constant (';' | ',')? { + +MessageList ::= '[' MessageValue (',' MessageValue)* ']' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue" + ] +} + +Field ::= FieldName (MessageField | ScalarField) (";" | ",")? { pin = 1 implements=[ - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement" - "io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufFieldAssign" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFieldAssign" ] +} + +private MessageField ::= ':'? ( MessageValue | MessageList ) + +private ScalarField ::= ':' ( ScalarValue | ScalarList ) { + pin = 1 } \ No newline at end of file diff --git a/src/main/grammar/protobuf.flex b/src/main/grammar/protobuf.flex index c6dd9b0d..79f1acc6 100644 --- a/src/main/grammar/protobuf.flex +++ b/src/main/grammar/protobuf.flex @@ -1,6 +1,6 @@ -package io.kanro.idea.plugin.protobuf.lang.lexer; +package io.kanro.idea.plugin.protobuf.lang.lexer.proto; -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens; +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens; import com.intellij.lexer.FlexLexer; import com.intellij.psi.tree.IElementType; @@ -92,6 +92,7 @@ String = {SingleQuotedString} | {DoubleQuotedString} "(" { return ProtobufTokens.LPAREN; } "<" { return ProtobufTokens.LT; } "-" { return ProtobufTokens.MINUS; } + "+" { return ProtobufTokens.PLUS; } "}" { return ProtobufTokens.RBRACE; } "]" { return ProtobufTokens.RBRACK; } ")" { return ProtobufTokens.RPAREN; } @@ -121,6 +122,7 @@ String = {SingleQuotedString} | {DoubleQuotedString} "service" { return ProtobufTokens.SERVICE; } "stream" { return ProtobufTokens.STREAM; } "syntax" { return ProtobufTokens.SYNTAX; } + "edition" { return ProtobufTokens.EDITION; } "to" { return ProtobufTokens.TO; } "true" { return ProtobufTokens.TRUE; } "false" { return ProtobufTokens.FALSE; } diff --git a/src/main/grammar/prototext.bnf b/src/main/grammar/prototext.bnf new file mode 100644 index 00000000..0a134d00 --- /dev/null +++ b/src/main/grammar/prototext.bnf @@ -0,0 +1,205 @@ +{ + generate=[names="long" psi="yes" tokens="no"] + parserClass="io.kanro.idea.plugin.protobuf.lang.psi.text.parser.ProtoTextParser" + parserUtilClass="io.kanro.idea.plugin.protobuf.lang.parser.ProtobufParserUtil" + parserImports=[ + "static io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens.*" + ] + psiClassPrefix="ProtoText" + psiImplClassSuffix="Impl" + psiPackage="io.kanro.idea.plugin.protobuf.lang.psi.text" + psiImplPackage="io.kanro.idea.plugin.protobuf.lang.psi.text.impl" + + implements="io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + extends="io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElementBase" + + elementTypeHolderClass="io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextTypes" + elementTypeClass="io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElementType" + + tokens = [ + SKIPPED_WHITESPACE = "regexp:[ \n\t\r\f]+" + + SHARP_LINE_COMMENT = "regexp:#[^\n]*\n?" + + IDENTIFIER_LITERAL = "regexp:[a-zA-Z_][a-zA-Z0-9_]*" + + INTEGER_LITERAL = "regexp:(0|[1-9][0-9]*)|(0[xX][0-9a-fA-F]+)|(0[0-7]+)" + FLOAT_LITERAL = "regexp:(\.[0-9]+|(0|[1-9][0-9]*)\.[0-9]*|(0|[1-9][0-9]*))([eE][-+]?[0-9]+)?" + + STRING_LITERAL = "regexp:('(\\.|[^'\n])*')|(\"(\\.|[^\"\n])*\")" + + ASSIGN = '=' + COMMA = ',' + DOT = '.' + GT = '>' + LBRACE = '{' + LBRACK = '[' + LPAREN = '(' + LT = '<' + MINUS = '-' + PLUS = '+' + RBRACE = '}' + RBRACK = ']' + RPAREN = ')' + SEMI = ';' + SLASH = '/' + COLON = ':' + + SYMBOL = "regexp:[!#$%&()*+,-./:;<=>?@\[\\\]^`{|}~]" + ] +} + +File ::= Field* { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue" + ] +} + +Field ::= FieldName (MessageField | ScalarField) (";" | ",")? { + pin = 1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner" + "io.kanro.idea.plugin.protobuf.lang.psi.text.feature.ProtoTextFieldAssign" + ] +} + +private MessageField ::= ':'? ( MessageValue | MessageList ) + +private ScalarField ::= ':' ( ScalarValue | ScalarList ) { + pin = 1 +} + +MessageList ::= '[' MessageValue (',' MessageValue)* ']' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue" + ] +} + +private MessageValue ::= BraceMessageValue | PointyMessageValue + +BraceMessageValue ::= '{' Field* '}' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue" + ] +} + +PointyMessageValue ::= '<' Field* '>' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue" + ] +} + +ScalarList ::= '[' ScalarValue (',' ScalarValue)* ']' { + pin=1 + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue" + ] +} + +ScalarValue ::= StringValue | NumberValue | BooleanValue | EnumValue { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.WrappedValue" + ] +} + +StringValue ::= STRING_LITERAL+ { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.StringValue" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.ReferenceElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.text.mixin.ProtoTextStringValueMixin" +} + +NumberValue ::= ('-' | '+')? (INTEGER_LITERAL | FLOAT_LITERAL | 'inf' | 'nan') { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.NumberValue" + ] +} + +BooleanValue ::= (false | true) { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.BooleanValue" + ] +} + +EnumValue ::= Identifier { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.value.EnumValue" + ] +} + +FieldName ::= SymbolName | ExtensionName | AnyName { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.text.mixin.ProtoTextFieldNameMixin" +} + +SymbolName ::= Identifier { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +TypeName ::= SymbolName ('.' TypeName)? { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + "io.kanro.idea.plugin.protobuf.lang.psi.feature.QualifiedElement" + ] + mixin="io.kanro.idea.plugin.protobuf.lang.psi.text.mixin.ProtoTextTypeNameMixin" +} + +Domain ::= Identifier ( '.' Identifier )* { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +ExtensionName ::= '[' TypeName ']' { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +AnyName ::= '[' Domain '/' TypeName ']' { + implements=[ + "io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement" + "io.kanro.idea.plugin.protobuf.lang.psi.type.FragmentElement" + ] +} + +private Identifier ::= IDENTIFIER_LITERAL diff --git a/src/main/grammar/prototext.flex b/src/main/grammar/prototext.flex new file mode 100644 index 00000000..de2e233a --- /dev/null +++ b/src/main/grammar/prototext.flex @@ -0,0 +1,130 @@ +package io.kanro.idea.plugin.protobuf.lang.lexer.text; + +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; + +%% + +%public +%class _ProtoTextLexer +%implements FlexLexer +%function advance +%type IElementType +%unicode +%state LINE_COMMENT, SHARP_LINE_COMMENT, BLOCK_COMMENT, AFTER_NUMBER + +// General classes +Alpha = [a-zA-Z_] +Digit = [0-9] +NonZeroDigit = [1-9] +HexDigit = [0-9a-fA-F] +OctDigit = [0-7] +Alphanumeric = {Alpha} | {Digit} + +// Catch-all for symbols not handled elsewhere. +// +// From tokenizer.h: +// Any other printable character, like '!' or '+'. Symbols are always a single character, so +// "!+$%" is four tokens. +Symbol = [!#$%&()*+,-./:;<=>?@\[\\\]\^`{|}~] + +// Whitespace. +WhitespaceNoNewline = [\ \t\r\f\x0b] // '\x0b' is '\v' (vertical tab) in C. +NewLine = "\n" +Whitespace = ({WhitespaceNoNewline} | {NewLine})+ + +// Comments. +SharpLineComments = ("#" [^\n]*) + +// Identifiers. +// +// From tokenizer.h: +// A sequence of letters, digits, and underscores, not starting with a digit. It is an error for +// a number to be followed by an identifier with no space in between. +Identifier = {Alpha} {Alphanumeric}* + +// Integers. +// +// From tokenizer.h: +// A sequence of digits representing an integer. Normally the digits are decimal, but a prefix of +// "0x" indicates a hex number and a leading zero indicates octal, just like with C numeric +// literals. A leading negative sign is NOT included in the token; it's up to the parser to +// interpret the unary minus operator on its own. +DecInteger = "0" | {NonZeroDigit} {Digit}* +OctInteger = "0" {OctDigit}+ +HexInteger = "0" [xX] {HexDigit}+ +Integer = {DecInteger} | {OctInteger} | {HexInteger} + +// Floats. +// +// From tokenizer.h: +// A floating point literal, with a fractional part and/or an exponent. Always in decimal. +// Again, never negative. +Float = ("." {Digit}+ {Exponent}? | {DecInteger} "." {Digit}* {Exponent}? | {DecInteger} {Exponent}) +Exponent = [eE] [-+]? {Digit}+ + +// Strings. +// +// From tokenizer.h: +// A quoted sequence of escaped characters. Either single or double quotes can be used, but they +// must match. A string literal cannot cross a line break. +SingleQuotedString = \' ([^\\\'\n] | \\[^\n])* (\' | \\)? +DoubleQuotedString = \" ([^\\\"\n] | \\[^\n])* (\" | \\)? +String = {SingleQuotedString} | {DoubleQuotedString} + +%% + + { + {Whitespace} { return com.intellij.psi.TokenType.WHITE_SPACE; } + + "=" { return ProtoTextTokens.ASSIGN; } + ":" { return ProtoTextTokens.COLON; } + "," { return ProtoTextTokens.COMMA; } + "." { return ProtoTextTokens.DOT; } + ">" { return ProtoTextTokens.GT; } + "{" { return ProtoTextTokens.LBRACE; } + "[" { return ProtoTextTokens.LBRACK; } + "(" { return ProtoTextTokens.LPAREN; } + "<" { return ProtoTextTokens.LT; } + "-" { return ProtoTextTokens.MINUS; } + "+" { return ProtoTextTokens.PLUS; } + "}" { return ProtoTextTokens.RBRACE; } + "]" { return ProtoTextTokens.RBRACK; } + ")" { return ProtoTextTokens.RPAREN; } + ";" { return ProtoTextTokens.SEMI; } + "/" { return ProtoTextTokens.SLASH; } + + "true" { return ProtoTextTokens.TRUE; } + "false" { return ProtoTextTokens.FALSE; } + + {Identifier} { return ProtoTextTokens.IDENTIFIER_LITERAL; } + {String} { return ProtoTextTokens.STRING_LITERAL; } + {Integer} { yybegin(AFTER_NUMBER); return ProtoTextTokens.INTEGER_LITERAL; } + {Float} { yybegin(AFTER_NUMBER); return ProtoTextTokens.FLOAT_LITERAL; } + + "#" { + yypushback(1); + yybegin(SHARP_LINE_COMMENT); + } + + // Additional unmatched symbols are matched individually as SYMBOL. + {Symbol} { return ProtoTextTokens.SYMBOL; } + + // All other unmatched characters. + [^] { return com.intellij.psi.TokenType.BAD_CHARACTER; } +} + + { + {SharpLineComments} { yybegin(YYINITIAL); return ProtoTextTokens.SHARP_LINE_COMMENT; } +} + + { + // An identifier immediately following a number (with no whitespace) is an error. We return + // the special IDENTIFIER_AFTER_NUMBER token type to signal this scenario. + {Identifier} { yybegin(YYINITIAL); return ProtoTextTokens.IDENTIFIER_AFTER_NUMBER; } + + // Any other token is valid. Push the token back and return to the initial state. + [^] { yybegin(YYINITIAL); yypushback(yylength()); } +} \ No newline at end of file diff --git a/src/main/java/io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParserUtil.java b/src/main/java/io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParserUtil.java index 9c425024..9703c6a8 100644 --- a/src/main/java/io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParserUtil.java +++ b/src/main/java/io/kanro/idea/plugin/protobuf/lang/parser/ProtobufParserUtil.java @@ -2,11 +2,11 @@ import com.intellij.lang.PsiBuilder; import com.intellij.lang.parser.GeneratedParserUtilBase; -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufKeywordToken; -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens; +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufKeywordToken; +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens; public class ProtobufParserUtil extends GeneratedParserUtilBase { - static boolean parseKeyword(PsiBuilder builder, int level) { + public static boolean parseKeyword(PsiBuilder builder, int level) { if (builder.eof()) { return false; } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/ProtobufIcons.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/ProtobufIcons.kt index c63dc0a3..5c21541f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/ProtobufIcons.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/ProtobufIcons.kt @@ -21,6 +21,7 @@ object ProtobufIcons { val MESSAGE: Icon = loadIcon("message.svg") val RESOURCE_MESSAGE: Icon = loadIcon("resource_message.svg") val FILE: Icon = loadIcon("protobuf_file.svg") + val TEXT_FILE: Icon = loadIcon("protobuf_text_file.svg") val LOGO: Icon = loadIcon("logo.svg") val FOLDER: Icon = PlatformIcons.FOLDER_ICON diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/Extension.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/Extension.kt index 5971a325..2d1b6b12 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/Extension.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/Extension.kt @@ -3,10 +3,9 @@ package io.kanro.idea.plugin.protobuf.aip import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition import io.kanro.idea.plugin.protobuf.lang.psi.nullCachedValue -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition internal fun ProtobufRpcDefinition.transcodingBody(): String? { return CachedValuesManager.getCachedValue(this) { @@ -14,7 +13,7 @@ internal fun ProtobufRpcDefinition.transcodingBody(): String? { options(AipOptions.httpOption).lastOrNull() ?: return@getCachedValue nullCachedValue() - val result = option.value(AipOptions.httpRuleBodyField)?.stringValue() ?: "" + val result = option.value(AipOptions.httpRuleBodyField)?.toString() ?: "" CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT) } } @@ -22,7 +21,7 @@ internal fun ProtobufRpcDefinition.transcodingBody(): String? { internal fun ProtobufRpcDefinition.resolveInput(): ProtobufMessageDefinition? { return CachedValuesManager.getCachedValue(this) { val input = - this.rpcIOList.firstOrNull()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + this.rpcIOList.firstOrNull()?.typeName?.resolve() as? ProtobufMessageDefinition ?: return@getCachedValue nullCachedValue() return@getCachedValue CachedValueProvider.Result.create(input, PsiModificationTracker.MODIFICATION_COUNT) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/annotator/AipAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/annotator/AipAnnotator.kt index 6529ba8e..0e97e5b5 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/annotator/AipAnnotator.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/annotator/AipAnnotator.kt @@ -7,14 +7,13 @@ import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.aip.quickfix.AddResourceImportFix import io.kanro.idea.plugin.protobuf.aip.reference.AipResourceReference +import io.kanro.idea.plugin.protobuf.aip.reference.AipTypeNameReference import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufFieldReferenceInString import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufRpcInputFieldReference import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufRpcOutputFieldReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor import io.kanro.idea.plugin.protobuf.lang.quickfix.AddImportFix -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufTypeNameReference class AipAnnotator : Annotator { override fun annotate( @@ -52,7 +51,7 @@ class AipAnnotator : Annotator { .create() } - is ProtobufTypeNameReference -> { + is AipTypeNameReference -> { holder.newAnnotation( HighlightSeverity.ERROR, "Type \"${o.value()}\" not found.", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/completion/AipCompletionContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/completion/AipCompletionContributor.kt index dad960f5..e187a89a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/completion/AipCompletionContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/completion/AipCompletionContributor.kt @@ -15,10 +15,10 @@ import com.intellij.util.ProcessingContext import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.aip.reference.AipResourceResolver import io.kanro.idea.plugin.protobuf.lang.completion.AutoPopupInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition import io.kanro.idea.plugin.protobuf.string.plural class AipCompletionContributor : CompletionContributor() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/method/AipSpecMethod.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/method/AipSpecMethod.kt index 817ce993..c590512a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/method/AipSpecMethod.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/method/AipSpecMethod.kt @@ -1,7 +1,7 @@ package io.kanro.idea.plugin.protobuf.aip.method import com.intellij.lang.annotation.AnnotationHolder -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition interface AipSpecMethod { val action: String diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/quickfix/AddResourceImportFix.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/quickfix/AddResourceImportFix.kt index 0083eda5..db05f417 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/quickfix/AddResourceImportFix.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/quickfix/AddResourceImportFix.kt @@ -8,12 +8,10 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import com.intellij.psi.stubs.StubIndex -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ResourceTypeIndex -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ResourceTypeIndex import io.kanro.idea.plugin.protobuf.lang.quickfix.ProtobufAddImportAction import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver @@ -60,10 +58,10 @@ class AddResourceImportFix( private fun createAction( project: Project, editor: Editor, - host: ProtobufSymbolReferenceHost, + host: ProtobufStringValue, elements: Array, ): ProtobufAddImportAction { - return ProtobufAddImportAction(project, editor, host, null, elements) + return ProtobufAddImportAction(project, editor, host, elements) } override fun getText(): String { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceReference.kt index 2489ae10..b3261acc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceReference.kt @@ -14,19 +14,17 @@ import io.kanro.idea.plugin.protobuf.aip.AipOptions import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler import io.kanro.idea.plugin.protobuf.lang.completion.ComposedInsertHandler import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFileOption -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stringRangeInParent -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ResourceTypeIndex -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFileOption +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stringRangeInParent +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ResourceTypeIndex import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver class AipResourceReference(element: ProtobufStringValue) : PsiReferenceBase(element) { override fun resolve(): PsiElement? { - val resourceName = element.stringLiteral.text.trim('"') + val resourceName = element.value() return AipResourceResolver.resolveAbsolutely(element.file(), resourceName) } @@ -93,7 +91,7 @@ class AipResourceReference(element: ProtobufStringValue) : PsiReferenceBase { val resourceName = - element.value(AipOptions.resourceTypeField)?.stringValue() ?: return null + element.value(AipOptions.resourceTypeField)?.toString() ?: return null LookupElementBuilder.create( resourceName, ).withLookupString(resourceName.substringAfterLast('/')) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceResolver.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceResolver.kt index e93afd12..43def145 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceResolver.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipResourceResolver.kt @@ -1,12 +1,11 @@ package io.kanro.idea.plugin.protobuf.aip.reference import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.public -import io.kanro.idea.plugin.protobuf.lang.psi.resolve -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.public +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren import java.util.Stack @@ -37,7 +36,7 @@ object AipResourceResolver { resourceName: String, ): ProtobufElement? { file.resourceDefinitions().forEach { - if (it.value(AipOptions.resourceTypeField)?.stringValue() == resourceName) { + if (it.value(AipOptions.resourceTypeField)?.toString() == resourceName) { return it } } @@ -75,7 +74,7 @@ object AipResourceResolver { result: MutableList = mutableListOf(), ): ProtobufElement? { file.resourceDefinitions().forEach { - if (it.value(AipOptions.resourceTypeField)?.stringValue() != null) { + if (it.value(AipOptions.resourceTypeField)?.toString() != null) { result += it } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipTypeNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipTypeNameReference.kt new file mode 100644 index 00000000..f9b74362 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/AipTypeNameReference.kt @@ -0,0 +1,140 @@ +package io.kanro.idea.plugin.protobuf.aip.reference + +import com.intellij.codeInsight.completion.CompletionUtilCore +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.stubs.StubIndex +import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stringRangeInParent +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix + +class AipTypeNameReference(element: ProtobufStringValue) : PsiReferenceBase(element) { + override fun resolve(): PsiElement? { + val typeName = QualifiedName.fromDottedString(element.value()) + return ProtobufSymbolResolver.resolveRelatively(element, typeName, ProtobufSymbolFilters.message) + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.stringRangeInParent() + } + + override fun getVariants(): Array { + val result = mutableListOf() + val addedElements = mutableSetOf() + val filter = ProtobufSymbolFilters.messageTypeName + + getVariantsInCurrentScope(filter, result, addedElements) + getVariantsInStubIndex(filter, result, addedElements) + return result.toTypedArray() + } + + private fun getVariantsInCurrentScope( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ) { + val parent = element.value().substringBeforeLast('.', "").split('.').filter { it.isNotEmpty() } + val parentScope = QualifiedName.fromComponents(parent) + ProtobufSymbolResolver.collectRelatively(element, parentScope, filter).forEach { + if (it in elements) return@forEach + result += lookupFor(it, parentScope) ?: return@forEach + elements += it + } + } + + private fun getVariantsInStubIndex( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ): Array { + val value = element.value() + if (value.contains('.')) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + + val searchName = value.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) + val scope = ProtobufRootResolver.searchScope(element) + val matcher = PlatformPatterns.string().contains(searchName) + val currentScope = element.parentOfType()?.scope() + + return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { + matcher.accepts(it) + }.flatMap { + StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) + .asSequence() + }.filter { + filter.isAccepted(it) + }.mapNotNull { + if (it in elements) return@mapNotNull null + result += lookupForStub(it, currentScope) ?: return@mapNotNull null + elements += it + }.toList().toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + val lookupElement = element as? LookupableElement ?: return null + val fullName = scope.append(lookupElement.name).toString() + var builder = lookupElement.lookup(fullName) ?: return null + if (element is ProtobufPackageName) { + builder = builder.withInsertHandler(packageInsertHandler) + } + return builder + } + + private fun lookupForStub( + element: ProtobufElement, + currentScope: QualifiedName?, + ): LookupElement? { + if (element !is ProtobufDefinition) return null + val qualifiedName = element.qualifiedName() ?: return null + + val targetName = + if (currentScope != null) { + qualifiedName.removeCommonPrefix(currentScope) + } else { + qualifiedName + } + return LookupElementBuilder.create(targetName).withLookupString(qualifiedName.lastComponent!!) + .withPresentableText(qualifiedName.lastComponent!!).withIcon(element.getIcon(false)) + .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) + .withTypeText(element.type()).withInsertHandler(AddImportInsertHandler(element)) + } + + override fun handleElementRename(newElementName: String): PsiElement { + val scope = element.value().substringBeforeLast('.', "") + val name = + if (scope.isEmpty()) { + newElementName + } else { + "$scope.$newElementName" + } + return element.replace(ProtobufPsiFactory.createStringValue(element.project, name)) + } + + companion object { + private val stringValueInsertHandler = SmartInsertHandler("\"") + + private val packageInsertHandler = SmartInsertHandler(".", 0, true) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/ProtobufFieldReferenceInString.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/ProtobufFieldReferenceInString.kt index 69af6d8b..7e6d2ecf 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/ProtobufFieldReferenceInString.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/ProtobufFieldReferenceInString.kt @@ -3,27 +3,26 @@ package io.kanro.idea.plugin.protobuf.aip.reference import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.PsiReferenceBase -import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.util.parentOfType import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stringRangeInParent +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike import io.kanro.idea.plugin.protobuf.lang.psi.realItems -import io.kanro.idea.plugin.protobuf.lang.psi.stringRangeInParent -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.text.feature.ProtoTextFieldAssign class ProtobufRpcInputFieldReference(field: ProtobufStringValue) : ProtobufFieldReferenceInString(field) { override fun message(): ProtobufMessageDefinition? { val rpc = element.parentOfType() as? ProtobufRpcDefinition ?: return null - return rpc.input()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + return rpc.input()?.typeName?.resolve() as? ProtobufMessageDefinition } } @@ -31,7 +30,7 @@ class ProtobufRpcOutputFieldReference(field: ProtobufStringValue) : ProtobufFieldReferenceInString(field) { override fun message(): ProtobufMessageDefinition? { val rpc = element.parentOfType() as? ProtobufRpcDefinition ?: return null - return rpc.output()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + return rpc.output()?.typeName?.resolve() as? ProtobufMessageDefinition } } @@ -57,7 +56,7 @@ abstract class ProtobufFieldReferenceInString(field: ProtobufStringValue) : return message()?.realItems()?.mapNotNull { (it as? ProtobufFieldLike)?.lookup()?.let { when (element.parent) { - is ProtobufFieldAssign -> it.withInsertHandler(insertHandler) + is ProtoTextFieldAssign -> it.withInsertHandler(insertHandler) is ProtobufOptionName -> it.withInsertHandler(insertHandler) else -> it } @@ -66,8 +65,7 @@ abstract class ProtobufFieldReferenceInString(field: ProtobufStringValue) : } override fun handleElementRename(newElementName: String): PsiElement { - (element.stringLiteral.node as? LeafElement)?.replaceWithText("\"$newElementName\"") - return element + return element.replace(ProtobufPsiFactory.createStringValue(element.project, newElementName)) } companion object { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/AipReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/AipReferenceContributor.kt index e7d1b331..e34694a9 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/AipReferenceContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/AipReferenceContributor.kt @@ -10,14 +10,16 @@ import com.intellij.psi.util.parentOfType import com.intellij.util.ProcessingContext import io.kanro.idea.plugin.protobuf.aip.AipOptions import io.kanro.idea.plugin.protobuf.aip.reference.AipResourceReference +import io.kanro.idea.plugin.protobuf.aip.reference.AipTypeNameReference import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufRpcInputFieldReference import io.kanro.idea.plugin.protobuf.aip.reference.ProtobufRpcOutputFieldReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike class AipReferenceContributor : PsiReferenceContributor() { override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { @@ -34,6 +36,13 @@ class AipReferenceContributor : PsiReferenceContributor() { .inside(ProtobufOptionAssign::class.java), AipFieldReferenceProvider(), ) + + registrar.registerReferenceProvider( + PlatformPatterns.psiElement(ProtobufStringValue::class.java) + .inside(ProtobufRpcDefinition::class.java) + .inside(ProtobufOptionAssign::class.java), + AipTypeNameReferenceProvider(), + ) } } @@ -50,18 +59,17 @@ class AipResourceReferenceProvider : PsiReferenceProvider() { private fun getReference(element: ProtobufStringValue): PsiReference? { val hover = element.parentOfType() ?: return null if (!hover.isOption(AipOptions.resourceReferenceOption)) return null - if (hover.value(AipOptions.resourceTypeField)?.stringValueList?.firstOrNull() == element) { - return AipResourceReference( - element, - ) - } - if (hover.value(AipOptions.resourceChildTypeField)?.stringValueList?.firstOrNull() == element) { + if (element.value().matches(resourceTypePattern)) { return AipResourceReference( element, ) } return null } + + companion object { + private val resourceTypePattern = Regex("""^(\w+\.)*\w+/(\w+\.)*\w+$""") + } } class AipFieldReferenceProvider : PsiReferenceProvider() { @@ -76,10 +84,36 @@ class AipFieldReferenceProvider : PsiReferenceProvider() { private fun getReference(element: ProtobufStringValue): PsiReference? { if (element.textMatches("\"*\"")) return null - val assign = element.parentOfType() ?: return null - val targetField = assign.field()?.qualifiedName() + val assign = element.parentOfType() ?: return null + val targetField = (assign.field() as? ProtobufFieldLike)?.qualifiedName() if (targetField == AipOptions.httpRuleBodyName) return ProtobufRpcInputFieldReference(element) if (targetField == AipOptions.httpRuleResponseBodyName) return ProtobufRpcOutputFieldReference(element) return null } } + +class AipTypeNameReferenceProvider : PsiReferenceProvider() { + override fun getReferencesByElement( + element: PsiElement, + context: ProcessingContext, + ): Array { + val stringValue = element as? ProtobufStringValue ?: return PsiReference.EMPTY_ARRAY + val reference = getReference(stringValue) ?: return PsiReference.EMPTY_ARRAY + return arrayOf(reference) + } + + private fun getReference(element: ProtobufStringValue): PsiReference? { + val assign = element.parentOfType() ?: return null + when (assign.field()?.qualifiedName()) { + AipOptions.lroMetadataName -> { + return AipTypeNameReference(element) + } + + AipOptions.lroResponseName -> { + return AipTypeNameReference(element) + } + + else -> return null + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/ProtobufTypeNameInStringProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/ProtobufTypeNameInStringProvider.kt index 932f5016..41526a29 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/ProtobufTypeNameInStringProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/aip/reference/contributor/ProtobufTypeNameInStringProvider.kt @@ -1,120 +1,104 @@ package io.kanro.idea.plugin.protobuf.aip.reference.contributor -import com.intellij.openapi.util.TextRange -import com.intellij.psi.impl.source.tree.LeafElement -import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValuesManager -import com.intellij.psi.util.PsiElementFilter -import com.intellij.psi.util.PsiModificationTracker -import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceProvider -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufValueAssign -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters -import io.kanro.idea.plugin.protobuf.string.splitToRange - -class ProtobufTypeNameInStringProvider : ProtobufSymbolReferenceProvider { - override fun hovers(element: ProtobufSymbolReferenceHost): ProtobufSymbolReferenceHover? { - if (element !is ProtobufStringValue) return null - return CachedValuesManager.getCachedValue(element) { - val assign = element.parentOfType() ?: return@getCachedValue null - val targetField = assign.field()?.qualifiedName() - return@getCachedValue when { - targetField == AipOptions.lroMetadataName -> { - CachedValueProvider.Result.create( - StringProtobufSymbolReferenceHover( - element, - ProtobufSymbolFilters.rpcTypeNameVariants, - ), - PsiModificationTracker.MODIFICATION_COUNT, - ) - } - targetField == AipOptions.lroResponseName -> { - CachedValueProvider.Result.create( - StringProtobufSymbolReferenceHover( - element, - ProtobufSymbolFilters.rpcTypeNameVariants, - ), - PsiModificationTracker.MODIFICATION_COUNT, - ) - } - else -> null - } - } - } -} - -class StringProtobufSymbolReferenceHover( - val element: ProtobufStringValue, - private val filter: PsiElementFilter, -) : ProtobufSymbolReferenceHover { - private var text = element.text - private val range: TextRange - private val parts: List - private val absolutely: Boolean - - init { - var range = element.textRange - var offset = 0 - if (text.startsWith('"')) { - text = text.substring(1) - offset += 1 - range = TextRange.create(range.startOffset + 1, range.endOffset) - } - if (text.startsWith('.')) { - absolutely = true - text = text.substring(1) - offset += 1 - range = TextRange.create(range.startOffset + 1, range.endOffset) - } else { - absolutely = false - } - if (text.endsWith('"')) { - text = text.substring(0, text.length - 1) - range = TextRange.create(range.startOffset, range.endOffset - 1) - } - this.range = range - - parts = - text.splitToRange('.').map { - val realRange = it.shiftRight(offset) - ProtobufSymbolReferenceHover.SymbolPart(realRange.startOffset, realRange.substring(element.text)) - } - } - - override fun textRange(): TextRange { - return range - } - - override fun symbolParts(): List { - return parts - } - - override fun renamePart( - index: Int, - newName: String, - ) { - val leaf = (element.stringLiteral.node as LeafElement) - val value = element.text - val part = symbolParts()[index] - val start = value.substring(0, part.startOffset) - val end = value.substring(part.startOffset + part.value.length, value.length) - leaf.replaceWithText("$start$newName$end") - } - - override fun rename(newName: String) { - val leaf = (element.stringLiteral.node as LeafElement) - leaf.replaceWithText("\"$newName\"") - } - - override fun absolutely(): Boolean { - return absolutely - } - - override fun variantFilter(): PsiElementFilter { - return filter - } -} +// class ProtobufTypeNameInStringProvider : ProtobufSymbolReferenceProvider { +// override fun hovers(element: ProtobufSymbolReferenceHost): ProtobufSymbolReferenceHover? { +// if (element !is ProtobufStringValue) return null +// return CachedValuesManager.getCachedValue(element) { +// val assign = element.parentOfType() ?: return@getCachedValue null +// val targetField = assign.field()?.qualifiedName() +// return@getCachedValue when { +// targetField == AipOptions.lroMetadataName -> { +// CachedValueProvider.Result.create( +// StringProtobufSymbolReferenceHover( +// element, +// ProtobufSymbolFilters.messageTypeName, +// ), +// PsiModificationTracker.MODIFICATION_COUNT, +// ) +// } +// +// targetField == AipOptions.lroResponseName -> { +// CachedValueProvider.Result.create( +// StringProtobufSymbolReferenceHover( +// element, +// ProtobufSymbolFilters.messageTypeName, +// ), +// PsiModificationTracker.MODIFICATION_COUNT, +// ) +// } +// +// else -> null +// } +// } +// } +// } +// +// class StringProtobufSymbolReferenceHover( +// val element: ProtobufStringValue, +// private val filter: PsiElementFilter, +// ) : ProtobufSymbolReferenceHover { +// private var text = element.text +// private val range: TextRange +// private val parts: List +// private val absolutely: Boolean +// +// init { +// var range = element.textRange +// var offset = 0 +// if (text.startsWith('"')) { +// text = text.substring(1) +// offset += 1 +// range = TextRange.create(range.startOffset + 1, range.endOffset) +// } +// if (text.startsWith('.')) { +// absolutely = true +// text = text.substring(1) +// offset += 1 +// range = TextRange.create(range.startOffset + 1, range.endOffset) +// } else { +// absolutely = false +// } +// if (text.endsWith('"')) { +// text = text.substring(0, text.length - 1) +// range = TextRange.create(range.startOffset, range.endOffset - 1) +// } +// this.range = range +// +// parts = +// text.splitToRange('.').map { +// val realRange = it.shiftRight(offset) +// ProtobufSymbolReferenceHover.SymbolPart(realRange.startOffset, realRange.substring(element.text)) +// } +// } +// +// override fun textRange(): TextRange { +// return range +// } +// +// override fun symbolParts(): List { +// return parts +// } +// +// override fun renamePart( +// index: Int, +// newName: String, +// ) { +// val value = element.value() +// val part = symbolParts()[index] +// val start = value.substring(0, part.startOffset) +// val end = value.substring(part.startOffset + part.value.length, value.length) +// element.replace(ProtobufPsiFactory.createStringValue(element.project, "$start$newName$end")) +// } +// +// override fun rename(newName: String) { +// element.replace(ProtobufPsiFactory.createStringValue(element.project, newName)) +// } +// +// override fun absolutely(): Boolean { +// return absolutely +// } +// +// override fun variantFilter(): PsiElementFilter { +// return filter +// } +// } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/Protoc.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/Protoc.kt index d58a555a..6745fefb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/Protoc.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/Protoc.kt @@ -7,9 +7,9 @@ import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve import java.lang.reflect.ParameterizedType import java.util.Stack diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/States.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/States.kt index bed054b7..a39e8722 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/States.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/States.kt @@ -9,16 +9,16 @@ import com.bybutter.sisyphus.protobuf.primitives.internal.MutableFileDescriptorP import com.bybutter.sisyphus.protobuf.primitives.internal.MutableMethodDescriptorProto import com.bybutter.sisyphus.protobuf.primitives.internal.MutableOneofDescriptorProto import com.bybutter.sisyphus.protobuf.primitives.internal.MutableServiceDescriptorProto -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition interface ProtobufCompilingState, TPsi : ProtobufElement> { fun target(): TDesc diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/EnumCompiler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/EnumCompiler.kt index 29cde894..03d2f280 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/EnumCompiler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/EnumCompiler.kt @@ -5,7 +5,7 @@ import io.kanro.idea.plugin.protobuf.compile.BaseProtobufCompilerPlugin import io.kanro.idea.plugin.protobuf.compile.CompileContext import io.kanro.idea.plugin.protobuf.compile.EnumCompilingState import io.kanro.idea.plugin.protobuf.compile.EnumValueCompilingState -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition class EnumCompiler : BaseProtobufCompilerPlugin() { override fun compile( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/FileCompiler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/FileCompiler.kt index 298a6455..73ea1ffb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/FileCompiler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/FileCompiler.kt @@ -9,10 +9,9 @@ import io.kanro.idea.plugin.protobuf.compile.EnumCompilingState import io.kanro.idea.plugin.protobuf.compile.FileCompilingState import io.kanro.idea.plugin.protobuf.compile.MessageCompilingState import io.kanro.idea.plugin.protobuf.compile.ServiceCompilingState -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class FileCompiler : BaseProtobufCompilerPlugin() { override fun compile( @@ -38,6 +37,7 @@ class FileCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufEnumDefinition -> { this.enumType += try { @@ -48,6 +48,7 @@ class FileCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufServiceDefinition -> { this.service += try { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/MessageCompiler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/MessageCompiler.kt index 7af28f91..54a2ec3a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/MessageCompiler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/MessageCompiler.kt @@ -13,16 +13,15 @@ import io.kanro.idea.plugin.protobuf.compile.MessageFieldCompilingState import io.kanro.idea.plugin.protobuf.compile.MessageMapEntryCompilingState import io.kanro.idea.plugin.protobuf.compile.MessageMapFieldCompilingState import io.kanro.idea.plugin.protobuf.compile.MessageOneofCompilingState -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.key -import io.kanro.idea.plugin.protobuf.lang.psi.optional -import io.kanro.idea.plugin.protobuf.lang.psi.repeated -import io.kanro.idea.plugin.protobuf.lang.psi.required +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.key +import io.kanro.idea.plugin.protobuf.lang.psi.proto.optional +import io.kanro.idea.plugin.protobuf.lang.psi.proto.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.required import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType import io.kanro.idea.plugin.protobuf.string.toPascalCase @@ -47,6 +46,7 @@ class MessageCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufEnumDefinition -> { this.enumType += try { @@ -57,6 +57,7 @@ class MessageCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufFieldDefinition -> { this.field += try { @@ -67,6 +68,7 @@ class MessageCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufOneofDefinition -> { this.oneofDecl += try { @@ -77,6 +79,7 @@ class MessageCompiler : BaseProtobufCompilerPlugin() { return@forEach } } + is ProtobufMapFieldDefinition -> { this.nestedType += try { @@ -123,7 +126,7 @@ class MessageFieldCompiler : BaseProtobufCompilerPlugin { @@ -131,6 +134,7 @@ class MessageFieldCompiler : BaseProtobufCompilerPlugin { this.type = FieldDescriptorProto.Type.ENUM this.typeName = type.qualifiedName()?.let { ".$it" } @@ -204,7 +208,7 @@ class MessageMapEntryCompiler : BaseProtobufCompilerPlugin { @@ -225,11 +229,13 @@ class MessageMapEntryCompiler : BaseProtobufCompilerPlugin { this.type = FieldDescriptorProto.Type.ENUM this.typeName = type.qualifiedName()?.let { ".$it" } ?: throw IllegalStateException("Invalid field definition: unresolvable value type.") } + else -> throw IllegalStateException("Invalid field definition: invalid value type.") } } @@ -268,6 +274,7 @@ class MessageMapFieldCompiler : BaseProtobufCompilerPlugin throw IllegalStateException("Invalid map field definition: unsupported extension map field.") } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/ServiceCompiler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/ServiceCompiler.kt index 5d1dadb8..beb5ddfb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/ServiceCompiler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/compile/basic/ServiceCompiler.kt @@ -5,9 +5,9 @@ import io.kanro.idea.plugin.protobuf.compile.BaseProtobufCompilerPlugin import io.kanro.idea.plugin.protobuf.compile.CompileContext import io.kanro.idea.plugin.protobuf.compile.ServiceCompilingState import io.kanro.idea.plugin.protobuf.compile.ServiceMethodCompilingState -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stream class ServiceCompiler : BaseProtobufCompilerPlugin() { override fun compile( @@ -43,10 +43,10 @@ class ServiceMethodCompiler : BaseProtobufCompilerPlugin, + stub: io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>, sink: IndexSink, ) { when (stub) { @@ -18,6 +17,7 @@ class GoIndexProvider : ProtobufIndexProvider { sink.occurrence(GoNameIndex.key, stub.unimplementedName() ?: return) sink.occurrence(GoUnimplementedServerNameIndex.key, stub.unimplementedName() ?: return) } + is ProtobufRpcStub -> { sink.occurrence(GoNameIndex.key, stub.funcName() ?: return) sink.occurrence( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoLineMarkerProvider.kt index 12514dbd..b71b6985 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoLineMarkerProvider.kt @@ -16,7 +16,7 @@ import com.intellij.psi.stubs.StubIndex import com.intellij.psi.util.elementType import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class GoLineMarkerProvider : RelatedItemLineMarkerProvider() { override fun collectNavigationMarkers( @@ -53,6 +53,7 @@ class GoLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implementing") result.add(builder.createLineMarkerInfo(element.firstLeaf())) } + is GoSpecType -> { val spec = parent.parent as? GoTypeSpec ?: return val type = spec.getGoUnderlyingType(null) as? GoStructType ?: return @@ -76,6 +77,7 @@ class GoLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implementing") result.add(builder.createLineMarkerInfo(element.firstLeaf())) } + else -> return } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoNameIndex.kt index 3f1e17f9..acf54d66 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.golang import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class GoNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoUnimplementedServerNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoUnimplementedServerNameIndex.kt index c9e023de..c392163e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoUnimplementedServerNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/GoUnimplementedServerNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.golang import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class GoUnimplementedServerNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/Names.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/Names.kt index abe23e62..223889a3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/Names.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/golang/Names.kt @@ -1,19 +1,18 @@ package io.kanro.idea.plugin.protobuf.golang -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub import io.kanro.idea.plugin.protobuf.string.toPascalCase fun ProtobufMessageDefinition.structName(): String? { @@ -26,7 +25,7 @@ fun ProtobufMessageDefinition.structName(): String? { fun ProtobufMessageStub.structName(): String? { return when (val owner = owner()) { - is ProtobufFileStub -> name() + is io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub -> name() is ProtobufMessageStub -> "${owner.structName()}_${name()}" else -> null } @@ -82,7 +81,7 @@ fun ProtobufEnumDefinition.typeName(): String? { fun ProtobufEnumStub.typeName(): String? { return when (val owner = owner()) { - is ProtobufFileStub -> name() + is io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub -> name() is ProtobufMessageStub -> "${owner.structName()}_${name()}" else -> null } @@ -103,7 +102,7 @@ fun ProtobufEnumValueStub.fieldName(): String? { val enum = owner() ?: return null val parent = when (val owner = enum.owner()) { - is ProtobufFileStub -> enum.name() + is io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub -> enum.name() is ProtobufMessageStub -> owner.structName() else -> null } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/Utils.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/Utils.kt index ed504b86..2e9e918e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/Utils.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/Utils.kt @@ -12,7 +12,7 @@ import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.grpc.index.ServiceMethodIndex import io.kanro.idea.plugin.protobuf.grpc.request.GrpcRequestExecutionSupport -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition fun JsonElement.injectedRequest(): HttpRequest? { val host = InjectedLanguageManager.getInstance(project).getInjectionHost(this) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/AipRunRequestGutterProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/AipRunRequestGutterProvider.kt index ef4e77f4..be1dbcfa 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/AipRunRequestGutterProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/AipRunRequestGutterProvider.kt @@ -14,11 +14,10 @@ import com.intellij.psi.PsiElement import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcOption import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.element.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufField +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcOption import javax.swing.Icon class AipRunRequestGutterProvider : RelatedItemLineMarkerProvider() { @@ -39,14 +38,14 @@ class AipRunRequestGutterProvider : RelatedItemLineMarkerProvider() { element: PsiElement, result: MutableCollection>, ) { - if (element !is ProtobufFieldAssign) return + if (element !is ProtobufField) return val option = element.parentOfType() ?: return val grpcDefinition = element.parentOfType() ?: return if (!option.isOption(AipOptions.httpOption)) return val fieldName = element.field()?.qualifiedName() ?: return if (fieldName !in AipOptions.httpRulesName) return val httpMethod = fieldName.lastComponent?.uppercase() ?: return - val path = element.constant?.stringValue() ?: return + val path = element.value()?.toString() ?: return val service = grpcDefinition.owner() ?: return val serviceName = service.qualifiedName() ?: return @@ -83,10 +82,9 @@ class AipRunRequestGutterProvider : RelatedItemLineMarkerProvider() { methodName: String, hasBody: Boolean, ): HttpRequestUrlPathInfo.Computed { - val raw = info.compute() return if (hasBody) { HttpRequestUrlPathInfo.Computed( - raw.baseInfo, + info, requestBody = RequestBody.CustomRequestBodyTemplate( TemplateImpl( @@ -98,7 +96,7 @@ class AipRunRequestGutterProvider : RelatedItemLineMarkerProvider() { ) } else { HttpRequestUrlPathInfo.Computed( - raw.baseInfo, + info, requestBody = RequestBody.CustomRequestBodyTemplate( TemplateImpl( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/GrpcRunRequestGutterProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/GrpcRunRequestGutterProvider.kt index c6925d66..0fc304cd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/GrpcRunRequestGutterProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/gutter/GrpcRunRequestGutterProvider.kt @@ -9,9 +9,9 @@ import com.intellij.httpClient.executor.util.unwrap import com.intellij.httpClient.http.request.microservices.OpenInHttpClientLineMarkerBuilder import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stream import javax.swing.Icon class GrpcRunRequestGutterProvider : RelatedItemLineMarkerProvider() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/MessageShortNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/MessageShortNameIndex.kt index e4daeeed..f53b804b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/MessageShortNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/MessageShortNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition class MessageShortNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndex.kt index c50a5476..5b5d07db 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition class ServiceMethodIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndexProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndexProvider.kt index 9b6ad4d4..638ddc86 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndexProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceMethodIndexProvider.kt @@ -1,15 +1,14 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.IndexSink -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufIndexProvider -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufIndexProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub class ServiceMethodIndexProvider : ProtobufIndexProvider { override fun buildIndex( - stub: ProtobufStub<*>, + stub: io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>, sink: IndexSink, ) { when (stub) { @@ -18,6 +17,7 @@ class ServiceMethodIndexProvider : ProtobufIndexProvider { sink.occurrence(MessageShortNameIndex.key, it) } } + is ProtobufServiceStub -> { stub.name()?.let { sink.occurrence(ServiceShortNameIndex.key, it) @@ -26,6 +26,7 @@ class ServiceMethodIndexProvider : ProtobufIndexProvider { sink.occurrence(ServiceQualifiedNameIndex.key, it.toString()) } } + is ProtobufRpcStub -> { sink.occurrence(ServiceMethodIndex.key, "${stub.owner()?.qualifiedName()}/${stub.name()}") } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceQualifiedNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceQualifiedNameIndex.kt index 23757c4f..9939ccad 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceQualifiedNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceQualifiedNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class ServiceQualifiedNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceShortNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceShortNameIndex.kt index a76f74cc..fbe08dfc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceShortNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/index/ServiceShortNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.grpc.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class ServiceShortNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/Extensions.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/Extensions.kt index 66c3d5dd..d2dd76a5 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/Extensions.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/Extensions.kt @@ -16,11 +16,10 @@ import io.kanro.idea.plugin.protobuf.aip.resolveInput import io.kanro.idea.plugin.protobuf.grpc.injectedRequest import io.kanro.idea.plugin.protobuf.grpc.isTranscoding import io.kanro.idea.plugin.protobuf.grpc.resolveRpc -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition import io.kanro.idea.plugin.protobuf.lang.psi.nullCachedValue -import io.kanro.idea.plugin.protobuf.lang.psi.resolveField -import io.kanro.idea.plugin.protobuf.lang.psi.resolveFieldType -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolveField +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolveFieldType internal fun JsonProperty.contextJsonObject(): JsonObject? { return CachedValuesManager.getCachedValue(this) { @@ -46,7 +45,7 @@ internal fun HttpRequest.grpcBodyType(): ProtobufMessageDefinition? { rpcDefinition.options(AipOptions.httpOption).lastOrNull() ?: return@getCachedValue nullCachedValue() val body = - option.value(AipOptions.httpRuleBodyField)?.stringValue() ?: return@getCachedValue nullCachedValue() + option.value(AipOptions.httpRuleBodyField)?.toString() ?: return@getCachedValue nullCachedValue() if (body != "*") { input.resolveFieldType(QualifiedName.fromDottedString(body), true) as? ProtobufMessageDefinition } else { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageEnumValueReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageEnumValueReference.kt index 1fe2defd..2e16cc29 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageEnumValueReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageEnumValueReference.kt @@ -7,11 +7,11 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiReferenceBase import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition import io.kanro.idea.plugin.protobuf.lang.psi.filterItem import io.kanro.idea.plugin.protobuf.lang.psi.firstItemOrNull +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition class GrpcMessageEnumValueReference(value: JsonStringLiteral) : PsiReferenceBase(value), @@ -23,7 +23,7 @@ class GrpcMessageEnumValueReference(value: JsonStringLiteral) : override fun resolve(): PsiElement? { val property = element.parent as? JsonProperty ?: return null val field = property.resolve() as? ProtobufFieldDefinition ?: return null - val enum = field.typeName.reference?.resolve() as? ProtobufEnumDefinition ?: return null + val enum = field.typeName.resolve() as? ProtobufEnumDefinition ?: return null return enum.firstItemOrNull { it.name() == element.value } } @@ -31,7 +31,7 @@ class GrpcMessageEnumValueReference(value: JsonStringLiteral) : val property = element.parent as? JsonProperty ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY val field = property.resolve() as? ProtobufFieldDefinition ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY val enum = - field.typeName.reference?.resolve() as? ProtobufEnumDefinition ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + field.typeName.resolve() as? ProtobufEnumDefinition ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY return enum.filterItem { true }.mapNotNull { it.lookup()?.withInsertHandler(SmartInsertHandler("\",")) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageFieldReference.kt index 023a1dba..e7f32804 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageFieldReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMessageFieldReference.kt @@ -15,15 +15,14 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiReferenceBase import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition import io.kanro.idea.plugin.protobuf.lang.psi.filterItem import io.kanro.idea.plugin.protobuf.lang.psi.firstItemOrNull -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes import kotlin.math.max @@ -115,7 +114,7 @@ private class JsonFieldSmartInsertHandler(private val element: ProtobufFieldLike if (element.repeated()) { LIST_INSERT_HANDLER } else { - when (val type = element.typeName.reference?.resolve()) { + when (val type = element.typeName.resolve()) { is ProtobufMessageDefinition -> { val name = type.qualifiedName().toString() if (name in WellknownTypes.types) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMethodReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMethodReference.kt index 39ac4a77..87f41322 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMethodReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcMethodReference.kt @@ -11,8 +11,8 @@ import com.intellij.psi.stubs.StubIndex import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.grpc.index.ServiceMethodIndex import io.kanro.idea.plugin.protobuf.grpc.index.ServiceQualifiedNameIndex -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class GrpcMethodReference(element: HttpRequestTarget, range: TextRange) : PsiReferenceBase(element, range) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcServiceReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcServiceReference.kt index d9cda53f..0d556ff7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcServiceReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcServiceReference.kt @@ -15,9 +15,9 @@ import com.intellij.psi.stubs.StubIndex import io.kanro.idea.plugin.protobuf.grpc.index.ServiceQualifiedNameIndex import io.kanro.idea.plugin.protobuf.grpc.index.ServiceShortNameIndex import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex class GrpcServiceReference(element: HttpRequestTarget, range: TextRange) : PsiReferenceBase(element, range) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTranscodingQueryReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTranscodingQueryReference.kt index 11bbfd06..d91b9578 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTranscodingQueryReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTranscodingQueryReference.kt @@ -13,8 +13,7 @@ import io.kanro.idea.plugin.protobuf.aip.transcodingBody import io.kanro.idea.plugin.protobuf.grpc.resolveRpc import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler import io.kanro.idea.plugin.protobuf.lang.psi.filterItem -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike class GrpcTranscodingQueryReference(private val name: String, element: HttpRequestTarget, range: TextRange) : PsiReferenceBase(element, range), GrpcReference { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTypeUrlReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTypeUrlReference.kt index d19a4b0d..5c8caa7a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTypeUrlReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcTypeUrlReference.kt @@ -11,9 +11,9 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StubIndex import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.grpc.index.MessageShortNameIndex -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex class GrpcTypeUrlReference(value: JsonStringLiteral) : PsiReferenceBase(value) { override fun calculateDefaultRangeInElement(): TextRange { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcUrlReferenceProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcUrlReferenceProvider.kt index 06687145..737a3b40 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcUrlReferenceProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/referece/GrpcUrlReferenceProvider.kt @@ -48,7 +48,11 @@ class GrpcTranscodingQueryReferenceProvider : PsiReferenceProvider() { if (!request.isTranscoding()) return PsiReference.EMPTY_ARRAY return element.query?.queryParameterList?.map { - GrpcTranscodingQueryReference(it.queryParameterKey.text ?: "", element, it.queryParameterKey.textRangeIn(element)) + GrpcTranscodingQueryReference( + it.queryParameterKey.text ?: "", + element, + it.queryParameterKey.textRangeIn(element), + ) }?.toTypedArray() ?: PsiReference.EMPTY_ARRAY } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestConverter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestConverter.kt index 4a295b7b..633ad27d 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestConverter.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestConverter.kt @@ -10,9 +10,9 @@ import com.intellij.openapi.project.DumbService import com.intellij.psi.SmartPsiElementPointer import io.grpc.Metadata import io.kanro.idea.plugin.protobuf.grpc.referece.GrpcMethodReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stream @Suppress("UnstableApiUsage") object GrpcRequestConverter : RequestConverter() { @@ -49,14 +49,15 @@ object GrpcRequestConverter : RequestConverter() { val rpc = element.requestTarget?.references?.filterIsInstance()?.firstOrNull() - ?.resolve() as? ProtobufRpcDefinition ?: throw IllegalStateException("Unsolvable rpc method '$method'.") + ?.resolve() as? ProtobufRpcDefinition + ?: throw IllegalStateException("Unsolvable rpc method '$method'.") val input = rpc.input() ?: throw IllegalStateException("Invalid rpc input.") val inputMessage = - rpc.input()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + rpc.input()?.typeName?.resolve() as? ProtobufMessageDefinition ?: throw IllegalStateException("Unsolvable rpc input '${input.typeName.text}'.") val output = rpc.output() ?: throw IllegalStateException("Invalid rpc input.") val outputMessage = - rpc.output()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + rpc.output()?.typeName?.resolve() as? ProtobufMessageDefinition ?: throw IllegalStateException("Unsolvable rpc input '${input.typeName.text}'.") GrpcRequest( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestHandler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestHandler.kt index 6f409fee..ff77d3c7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestHandler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/GrpcRequestHandler.kt @@ -19,7 +19,7 @@ import io.grpc.Metadata import io.grpc.MethodDescriptor import io.grpc.Status import io.kanro.idea.plugin.protobuf.grpc.referece.GrpcMethodReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import java.util.concurrent.TimeUnit diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/ProtoFileReflection.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/ProtoFileReflection.kt index e27e2dd7..953715da 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/ProtoFileReflection.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/grpc/request/ProtoFileReflection.kt @@ -8,8 +8,8 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StubIndex import io.kanro.idea.plugin.protobuf.compile.Protoc -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex class ProtoFileReflection(private val context: ProtobufElement) : LocalProtoReflection() { private val wellknownProtoFiles = diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Extension.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Extension.kt index b6281b91..41275a82 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Extension.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Extension.kt @@ -7,12 +7,12 @@ import com.intellij.psi.PsiEnumConstant import com.intellij.psi.PsiMethod import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike import io.kanro.idea.plugin.protobuf.sisyphus.isSisyphus fun PsiElement.findJavaClass(name: QualifiedName?): PsiClass? { @@ -37,6 +37,7 @@ fun ProtobufFieldLike.toGetters(): Array { is ProtobufMessageDefinition -> owner.toBuilderClass()?.findMethodsByName(getterName(), true) ?: PsiMethod.EMPTY_ARRAY + else -> PsiMethod.EMPTY_ARRAY } } @@ -46,6 +47,7 @@ fun ProtobufFieldLike.toSetters(): Array { is ProtobufMessageDefinition -> owner.toBuilderClass()?.findMethodsByName(setterName(), true) ?: PsiMethod.EMPTY_ARRAY + else -> PsiMethod.EMPTY_ARRAY } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/FileJavaOptionsProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/FileJavaOptionsProvider.kt index abc11faf..b564d6ef 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/FileJavaOptionsProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/FileJavaOptionsProvider.kt @@ -1,15 +1,11 @@ package io.kanro.idea.plugin.protobuf.java -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubExternalProvider -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubSupport -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubExternalProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubSupport +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub class FileJavaOptionsProvider : ProtobufStubExternalProvider { override fun mergeExternalData( @@ -43,14 +39,14 @@ class FileJavaOptionsProvider : ProtobufStubExternalProvider { fun ProtobufFieldLike.jsonName(): String? { return if (this is ProtobufOptionOwner) { - options("json_name").lastOrNull()?.value()?.stringValue() + options("json_name").lastOrNull()?.value()?.toString() } else { null } } fun ProtobufFieldLikeStub.jsonName(): String? { - return if (this is ProtobufStub<*>) { + return if (this is io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>) { externalData("json_name") } else { null @@ -58,25 +54,25 @@ fun ProtobufFieldLikeStub.jsonName(): String? { } fun ProtobufFile.javaPackage(): String? { - return options("java_package").lastOrNull()?.value()?.stringValue() + return options("java_package").lastOrNull()?.value()?.toString() } fun ProtobufFile.javaOuterClassname(): String? { - return options("java_outer_classname").lastOrNull()?.value()?.stringValue() + return options("java_outer_classname").lastOrNull()?.value()?.toString() } fun ProtobufFile.javaMultipleFiles(): Boolean? { - return options("java_multiple_files").lastOrNull()?.value()?.booleanValue?.value() + return options("java_multiple_files").lastOrNull()?.value() as? Boolean } -fun ProtobufFileStub.javaPackage(): String? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.javaPackage(): String? { return externalData("java_package") } -fun ProtobufFileStub.javaOuterClassname(): String? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.javaOuterClassname(): String? { return externalData("java_outer_classname") } -fun ProtobufFileStub.javaMultipleFiles(): Boolean? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.javaMultipleFiles(): Boolean? { return externalData("java_multiple_files")?.let { it == "true" } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaFindUsageFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaFindUsageFactory.kt index ea66bcbe..ba2aac1e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaFindUsageFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaFindUsageFactory.kt @@ -3,13 +3,13 @@ package io.kanro.idea.plugin.protobuf.java import com.intellij.find.findUsages.FindUsagesHandler import com.intellij.find.findUsages.FindUsagesHandlerFactory import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike class JavaFindUsageFactory : FindUsagesHandlerFactory() { override fun canFindUsages(element: PsiElement): Boolean { @@ -35,9 +35,11 @@ class JavaFindUsageFactory : FindUsagesHandlerFactory() { ).toTypedArray(), ) } + is ProtobufEnumDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toClass()).toTypedArray()) } + is ProtobufServiceDefinition -> { ProtoDefinitionFindUsage( element, @@ -50,9 +52,11 @@ class JavaFindUsageFactory : FindUsagesHandlerFactory() { ).toTypedArray(), ) } + is ProtobufEnumValueDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toEnumConstant()).toTypedArray()) } + is ProtobufRpcDefinition -> { ProtoDefinitionFindUsage( element, @@ -65,12 +69,14 @@ class JavaFindUsageFactory : FindUsagesHandlerFactory() { ).toTypedArray(), ) } + is ProtobufFieldLike -> { ProtoDefinitionFindUsage( element, listOfNotNull(*element.toGetters(), *element.toSetters()).toTypedArray(), ) } + else -> null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaIndexProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaIndexProvider.kt index 30726c49..6df0538a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaIndexProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaIndexProvider.kt @@ -1,14 +1,13 @@ package io.kanro.idea.plugin.protobuf.java import com.intellij.psi.stubs.IndexSink -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufIndexProvider -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufIndexProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub class JavaIndexProvider : ProtobufIndexProvider { override fun buildIndex( - stub: ProtobufStub<*>, + stub: io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>, sink: IndexSink, ) { when (stub) { @@ -22,6 +21,7 @@ class JavaIndexProvider : ProtobufIndexProvider { sink.occurrence(JavaNameIndex.key, stub.fullFutureStubName().toString()) sink.occurrence(JavaNameIndex.key, stub.fullCoroutineStubName().toString()) } + is ProtobufRpcStub -> { val methodName = stub.methodName() diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaLineMarkerProvider.kt index 0fcf5405..fce7d447 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaLineMarkerProvider.kt @@ -9,10 +9,10 @@ import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.uast.UClass @@ -39,6 +39,7 @@ class JavaLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implementing") result.add(builder.createLineMarkerInfo(element.firstLeaf())) } + is UMethod -> { val method = findMethodProtobufDefinition(parent) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaNameIndex.kt index 4b94d438..f9eab269 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/JavaNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.java import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class JavaNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Names.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Names.kt index 1943d688..9aeaf944 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Names.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/Names.kt @@ -1,20 +1,19 @@ package io.kanro.idea.plugin.protobuf.java import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub import io.kanro.idea.plugin.protobuf.lang.util.toQualifiedName import io.kanro.idea.plugin.protobuf.string.toCamelCase @@ -22,7 +21,7 @@ fun ProtobufFile.fullPackageName(): QualifiedName? { return javaPackage()?.toQualifiedName() ?: scope() } -fun ProtobufFileStub.fullPackageName(): QualifiedName? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.fullPackageName(): QualifiedName? { return javaPackage()?.toQualifiedName() ?: scope() } @@ -34,7 +33,7 @@ fun ProtobufFile.fullOuterClassName(): QualifiedName? { } } -fun ProtobufFileStub.fullOuterClassName(): QualifiedName? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.fullOuterClassName(): QualifiedName? { return if (javaMultipleFiles() == true) { fullPackageName() } else { @@ -65,6 +64,7 @@ fun ProtobufMessageDefinition.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -76,6 +76,7 @@ fun ProtobufMessageStub.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -94,11 +95,13 @@ fun ProtobufMessageDefinition.fullMessageOrBuilderName(): QualifiedName? { owner.fullOuterClassName()?.append(messageOrBuilderName()) ?: QualifiedName.fromComponents( messageOrBuilderName(), ) + is ProtobufMessageDefinition -> owner.fullClassName()?.append(messageOrBuilderName()) ?: QualifiedName.fromComponents( messageOrBuilderName(), ) + else -> null } } @@ -109,11 +112,13 @@ fun ProtobufMessageStub.fullBuilderClassName(): QualifiedName? { owner.fullOuterClassName()?.append(messageOrBuilderName()) ?: QualifiedName.fromComponents( messageOrBuilderName(), ) + is ProtobufMessageDefinition -> owner.fullClassName()?.append(messageOrBuilderName()) ?: QualifiedName.fromComponents( messageOrBuilderName(), ) + else -> null } } @@ -285,6 +290,7 @@ fun ProtobufEnumDefinition.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -296,6 +302,7 @@ fun ProtobufEnumStub.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/ProtobufLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/ProtobufLineMarkerProvider.kt index 0de64b3a..abc33d07 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/ProtobufLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/java/ProtobufLineMarkerProvider.kt @@ -7,9 +7,9 @@ import com.intellij.psi.PsiElement import com.intellij.psi.search.searches.DirectClassInheritorsSearch import com.intellij.psi.search.searches.OverridingMethodsSearch import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class ProtobufLineMarkerProvider : RelatedItemLineMarkerProvider() { override fun collectNavigationMarkers( @@ -36,6 +36,7 @@ class ProtobufLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implemented") result.add(builder.createLineMarkerInfo(element.identifierLiteral ?: element)) } + is ProtobufServiceDefinition -> { val apis = owner.toImplBaseClass()?.let { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextFileType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextFileType.kt new file mode 100644 index 00000000..46939e58 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextFileType.kt @@ -0,0 +1,33 @@ +package io.kanro.idea.plugin.protobuf.lang + +import com.intellij.openapi.fileTypes.LanguageFileType +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes +import javax.swing.Icon + +class ProtoTextFileType : LanguageFileType(ProtoTextLanguage) { + companion object { + val INSTANCE = ProtoTextFileType() + + init { + // Workaround for issue #164 + ProtobufStubTypes + } + } + + override fun getName(): String { + return ProtoTextLanguage.id + } + + override fun getDescription(): String { + return "Protocol Buffer Text Format" + } + + override fun getDefaultExtension(): String { + return "txtpb" + } + + override fun getIcon(): Icon { + return ProtobufIcons.TEXT_FILE + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextLanguage.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextLanguage.kt new file mode 100644 index 00000000..c53f9155 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextLanguage.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang + +import com.intellij.lang.Language + +object ProtoTextLanguage : Language("prototext") diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextParserDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextParserDefinition.kt new file mode 100644 index 00000000..d5eed168 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtoTextParserDefinition.kt @@ -0,0 +1,53 @@ +package io.kanro.idea.plugin.protobuf.lang + +import com.intellij.lang.ASTNode +import com.intellij.lang.ParserDefinition +import com.intellij.lang.PsiParser +import com.intellij.lexer.Lexer +import com.intellij.openapi.project.Project +import com.intellij.psi.FileViewProvider +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.tree.IFileElementType +import com.intellij.psi.tree.TokenSet +import io.kanro.idea.plugin.protobuf.lang.lexer.ProtoTextLexer +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextTypes +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextFileImpl +import io.kanro.idea.plugin.protobuf.lang.psi.text.parser.ProtoTextParser +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextParserDefinition : ParserDefinition { + override fun createLexer(project: Project): Lexer { + return ProtoTextLexer() + } + + override fun createParser(project: Project): PsiParser { + return ProtoTextParser() + } + + override fun getFileNodeType(): IFileElementType { + return ProtoTextFile.Type + } + + override fun getCommentTokens(): TokenSet { + return comments + } + + override fun getStringLiteralElements(): TokenSet { + return string + } + + override fun createElement(node: ASTNode): PsiElement { + return ProtoTextTypes.Factory.createElement(node) + } + + override fun createFile(viewProvider: FileViewProvider): PsiFile { + return ProtoTextFileImpl(viewProvider) + } + + companion object { + val comments = TokenSet.create(ProtoTextTokens.SHARP_LINE_COMMENT) + val string = TokenSet.create(ProtoTextTokens.STRING_LITERAL) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufFileType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufFileType.kt index 8eb1ad7a..4b30e01c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufFileType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufFileType.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.lang import com.intellij.openapi.fileTypes.LanguageFileType import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufStubTypes +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes import javax.swing.Icon class ProtobufFileType : LanguageFileType(ProtobufLanguage) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufParserDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufParserDefinition.kt index dba5cd55..943aae65 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufParserDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ProtobufParserDefinition.kt @@ -11,11 +11,11 @@ import com.intellij.psi.PsiFile import com.intellij.psi.tree.IFileElementType import com.intellij.psi.tree.TokenSet import io.kanro.idea.plugin.protobuf.lang.lexer.ProtobufLexer -import io.kanro.idea.plugin.protobuf.lang.parser.ProtobufParser -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypes -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufFileImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypes +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufFileImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.parser.ProtobufParser +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufParserDefinition : ParserDefinition { override fun createLexer(project: Project): Lexer { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/actions/ArrangeFieldsNumberAction.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/actions/ArrangeFieldsNumberAction.kt index 83c23911..219151c7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/actions/ArrangeFieldsNumberAction.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/actions/ArrangeFieldsNumberAction.kt @@ -11,9 +11,9 @@ import com.intellij.openapi.editor.actionSystem.EditorActionHandler import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.proto.element.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope abstract class ArrangeFieldsNumberActionHandler : EditorActionHandler() { private fun findItemsToSort( @@ -89,7 +89,7 @@ class ArrangeFieldsNumberToMaxHandler : ArrangeFieldsNumberActionHandler() { val maxInItems = items.maxOf { it.number() ?: -1 }.takeIf { it >= numbersNeed } var current = - if (items.first() is ProtobufEnumValue) { + if (items.first() is ProtobufEnumValueDefinition) { maxInItems ?: (numbersNeed - 1) } else { maxInItems ?: numbersNeed @@ -115,7 +115,7 @@ class ArrangeFieldsNumberToMaxHandler : ArrangeFieldsNumberActionHandler() { val numbersNeed = items.size.toLong() val maxInItems = items.maxOf { it.number() ?: -1 }.takeIf { it >= numbersNeed } var current = - if (items.first() is ProtobufEnumValue) { + if (items.first() is ProtobufEnumValueDefinition) { maxInItems ?: (numbersNeed - 1) } else { maxInItems ?: numbersNeed @@ -146,7 +146,7 @@ class ArrangeFieldsNumberFromMinHandler : ArrangeFieldsNumberActionHandler() { val minInItems = items.minOf { it.number() ?: -1 }.takeIf { it >= 0 } var current = - if (items.first() is ProtobufEnumValue) { + if (items.first() is ProtobufEnumValueDefinition) { minInItems ?: 0 } else { minInItems ?: 1 diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/FileTracker.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/FileTracker.kt index 1ac37967..5024e378 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/FileTracker.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/FileTracker.kt @@ -7,13 +7,13 @@ import com.intellij.psi.tree.TokenSet import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypes import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFileReferenceContributor -import io.kanro.idea.plugin.protobuf.lang.psi.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypes +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufFileReferenceContributor +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren import io.kanro.idea.plugin.protobuf.lang.quickfix.OptimizeImportsFix import io.kanro.idea.plugin.protobuf.lang.util.asFilter @@ -35,7 +35,7 @@ open class FileTracker(file: ProtobufFile) { statement: ProtobufImportStatement, holder: AnnotationHolder, ) { - val file = statement.stringValue?.stringLiteral?.text?.trim('"') ?: return + val file = statement.stringValue?.value() ?: return if ((imported[file]?.size ?: 0) > 1) { createDuplicate(statement, file, holder) return @@ -60,7 +60,7 @@ open class FileTracker(file: ProtobufFile) { } protected open fun record(statement: ProtobufImportStatement) { - val file = statement.stringValue?.stringLiteral?.text?.trim('"') ?: return + val file = statement.stringValue?.value() ?: return imported.getOrPut(file) { mutableSetOf() }.add(statement) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/NumberTracker.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/NumberTracker.kt index fa508f1f..f8e0dac3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/NumberTracker.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/NumberTracker.kt @@ -5,17 +5,18 @@ import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedRange -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumbered -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItem -import io.kanro.idea.plugin.protobuf.lang.psi.range +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.range +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem import io.kanro.idea.plugin.protobuf.lang.psi.realItems -open class NumberTracker(scope: ProtobufNumberScope, val minValue: Long) { +open class NumberTracker(scope: ProtobufNumberScope) { private val numberMap = mutableMapOf>() - private val reservedNameMap = mutableMapOf() + private val reservedNameMap = mutableMapOf() private val allowAlias = scope.allowAlias() init { @@ -36,14 +37,17 @@ open class NumberTracker(scope: ProtobufNumberScope, val minValue: Long) { reservedNameMap[range] = reserved } + protected open fun record(reserved: ProtobufExtensionRange) { + val range = reserved.range() ?: return + reservedNameMap[range] = reserved + } + open fun visit( numbered: ProtobufNumbered, holder: AnnotationHolder, ) { val number = numbered.number() ?: return createError(numbered, buildMessage(number, numbered) ?: return, holder) - if (number < minValue) { - } } open fun visit( @@ -58,7 +62,6 @@ open class NumberTracker(scope: ProtobufNumberScope, val minValue: Long) { number: Long, numbered: ProtobufNumbered, ): String? { - if (number < minValue) return "Wrong number, the min value is $minValue" reservedNameMap.forEach { (range, element) -> if (range.contains(number)) { return "Number reserved: \"${element.text}\"" @@ -110,14 +113,8 @@ open class NumberTracker(scope: ProtobufNumberScope, val minValue: Long) { companion object { fun tracker(scope: ProtobufNumberScope): NumberTracker { return CachedValuesManager.getCachedValue(scope) { - val minValue = - if (scope is ProtobufMessageDefinition) { - 1L - } else { - 0L - } CachedValueProvider.Result.create( - NumberTracker(scope, minValue), + NumberTracker(scope), PsiModificationTracker.MODIFICATION_COUNT, ) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtoTextAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtoTextAnnotator.kt new file mode 100644 index 00000000..ab0ca0ad --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtoTextAnnotator.kt @@ -0,0 +1,156 @@ +package io.kanro.idea.plugin.protobuf.lang.annotator + +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.lang.annotation.HighlightSeverity +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiElement +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextAnyName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextField +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextVisitor +import io.kanro.idea.plugin.protobuf.lang.psi.text.enum +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextHeaderFileReference +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextHeaderMessageReference +import io.kanro.idea.plugin.protobuf.lang.psi.text.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue +import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes + +class ProtoTextAnnotator : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + if (element !is ProtoTextElement) { + return + } + element.accept( + object : ProtoTextVisitor() { + override fun visitComment(comment: PsiComment) { + when (val reference = comment.reference) { + is ProtoTextHeaderFileReference -> { + if (reference.resolve() == null) { + holder.newAnnotation( + HighlightSeverity.WARNING, + "Schema file '${reference.fileName()}' not found", + ).range(reference.absoluteRange).highlightType(ProblemHighlightType.WARNING).create() + } + } + + is ProtoTextHeaderMessageReference -> { + if (reference.resolve() == null) { + holder.newAnnotation( + HighlightSeverity.WARNING, + "Message '${reference.messageName()}' not found", + ).range(reference.absoluteRange).highlightType(ProblemHighlightType.WARNING).create() + } + } + } + } + + override fun visitEnumValue(o: ProtoTextEnumValue) { + if (o.file()?.schema() == null) return + + val enum = o.enum() ?: return + enum.items { + if (it.name() == o.text) { + return + } + } + holder.newAnnotation( + HighlightSeverity.ERROR, + "Enum value '${o.text}' not found", + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() + } + + override fun visitFieldName(o: ProtoTextFieldName) { + if (o.file()?.schema() == null) return + + if (o.resolve() == null) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${o.text}' not existed", + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() + } + } + + override fun visitField(o: ProtoTextField) { + visitValueAssign(o) + } + + private fun visitValueAssign(o: ValueAssign) { + val field = o.field() ?: return + val valueElement = o.valueElement() ?: return + + if (valueElement is ArrayValue) { + when (field) { + is ProtobufFieldDefinition -> { + if (!field.repeated()) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.name()}' is not a repeated field", + ).range(field.textRange).create() + } + } + + is ProtobufGroupDefinition -> { + if (!field.repeated()) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.name()}' is not a repeated field", + ).range(field.textRange).create() + } + } + } + + valueElement.values().forEach { + checkCompatibleType(it, field) + } + } else { + checkCompatibleType(valueElement, field) + } + } + + private fun checkCompatibleType( + value: ValueElement<*>, + field: ProtobufFieldLike, + ) { + val fieldType = field.fieldValueType() + val valueType = value.valueType() + if (valueType != fieldType) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.fieldName()}' required ${fieldType.name.lowercase()} value, but got ${valueType.name.lowercase()} value", + ).range(value.textRange).create() + } + } + + override fun visitAnyName(o: ProtoTextAnyName) { + if (o.file()?.schema() == null) return + + val parentField = o.parentOfType()?.parentOfType()?.field() + + if (parentField !is ProtobufFieldDefinition || (parentField.typeName.resolve() as? ProtobufMessageDefinition)?.qualifiedName()?.toString() != WellknownTypes.ANY) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${parentField?.name()}' is not a field with Any type", + ).range(o.textRange).highlightType(ProblemHighlightType.ERROR).create() + } + } + }, + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf2Annotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf2Annotator.kt index e74d2bcc..5b9e931f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf2Annotator.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf2Annotator.kt @@ -4,20 +4,22 @@ import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor class Protobuf2Annotator : Annotator { override fun annotate( element: PsiElement, holder: AnnotationHolder, ) { + if (element.containingFile.originalFile !is ProtobufFile) return val file = (element as? ProtobufElement)?.file() ?: return val syntax = file.syntax() - if (syntax != null && syntax != "proto2") return + if ((syntax != null && syntax != "proto2") || file.edition() != null) return element.accept( object : ProtobufVisitor() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf3Annotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf3Annotator.kt index 366f168d..b18ed6dd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf3Annotator.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/Protobuf3Annotator.kt @@ -4,21 +4,22 @@ import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.isFieldDefaultOption -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.weak +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor +import io.kanro.idea.plugin.protobuf.lang.psi.proto.isFieldDefaultOption +import io.kanro.idea.plugin.protobuf.lang.psi.proto.weak import io.kanro.idea.plugin.protobuf.lang.support.Options class Protobuf3Annotator : Annotator { @@ -26,6 +27,7 @@ class Protobuf3Annotator : Annotator { element: PsiElement, holder: AnnotationHolder, ) { + if (element.containingFile.originalFile !is ProtobufFile) return val file = (element as? ProtobufElement)?.file() ?: return if (file.syntax() != "proto3") return @@ -54,7 +56,7 @@ class Protobuf3Annotator : Annotator { override fun visitExtendDefinition(o: ProtobufExtendDefinition) { val typename = o.typeName ?: return - val name = (typename.reference?.resolve() as? ProtobufMessageDefinition)?.qualifiedName() ?: return + val name = (typename.resolve() as? ProtobufMessageDefinition)?.qualifiedName() ?: return if (Options.all.contains(name)) { return } @@ -95,7 +97,7 @@ class Protobuf3Annotator : Annotator { } } - override fun visitBuiltInOptionName(o: ProtobufBuiltInOptionName) { + override fun visitOptionName(o: ProtobufOptionName) { if (o.isFieldDefaultOption()) { holder.newAnnotation( HighlightSeverity.ERROR, @@ -121,7 +123,7 @@ class Protobuf3Annotator : Annotator { .create() } else if (zeroDefinition != first) { holder.newAnnotation( - HighlightSeverity.WARNING, + HighlightSeverity.WEAK_WARNING, "'${zeroDefinition.name()}' needs be first element in proto3 for compatibility with the proto2.", ) .range(o.textRange) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufAnnotator.kt index 669377ea..22540301 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufAnnotator.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufAnnotator.kt @@ -7,47 +7,48 @@ import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.PsiElement import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.highligh.ProtobufHighlighter -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufArrayValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufConstant -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedRange -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.enum -import io.kanro.idea.plugin.protobuf.lang.psi.field -import io.kanro.idea.plugin.protobuf.lang.psi.float -import io.kanro.idea.plugin.protobuf.lang.psi.int +import io.kanro.idea.plugin.protobuf.lang.highlight.ProtobufHighlighter +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.message -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumbered -import io.kanro.idea.plugin.protobuf.lang.psi.range -import io.kanro.idea.plugin.protobuf.lang.psi.uint +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufAnyName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufField +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor +import io.kanro.idea.plugin.protobuf.lang.psi.proto.enum +import io.kanro.idea.plugin.protobuf.lang.psi.proto.range +import io.kanro.idea.plugin.protobuf.lang.psi.proto.repeated +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.value.ArrayValue +import io.kanro.idea.plugin.protobuf.lang.psi.value.IntegerValue import io.kanro.idea.plugin.protobuf.lang.quickfix.AddImportFix import io.kanro.idea.plugin.protobuf.lang.quickfix.RenameFix -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufTypeNameReference import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType +import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes import io.kanro.idea.plugin.protobuf.string.case.CaseFormat import io.kanro.idea.plugin.protobuf.string.toCase import io.kanro.idea.plugin.protobuf.string.toScreamingSnakeCase @@ -85,12 +86,9 @@ class ProtobufAnnotator : Annotator { val name = o.name() ?: return if (name != name.toCase(case)) { holder.newAnnotation( - HighlightSeverity.WARNING, + HighlightSeverity.WEAK_WARNING, "$type should be ${case.name.toCase(case)}", - ) - .range(o.identifier()?.textRange ?: o.textRange) - .withFix(RenameFix(name.toCase(case))) - .create() + ).range(o.identifier()?.textRange ?: o.textRange).withFix(RenameFix(name.toCase(case))).create() } } @@ -111,10 +109,9 @@ class ProtobufAnnotator : Annotator { holder.newAnnotation( HighlightSeverity.ERROR, "$keyType is not a valid key type of map", - ) - .range(types[0].textRange) - .create() + ).range(types[0].textRange).create() } + visitFieldLike(o) } override fun visitImportStatement(o: ProtobufImportStatement) { @@ -122,200 +119,98 @@ class ProtobufAnnotator : Annotator { } override fun visitTypeName(o: ProtobufTypeName) { - if (o.symbolNameList.size == 1 && BuiltInType.isBuiltInType(o.text)) { - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(o.textRange) - .textAttributes(ProtobufHighlighter.KEYWORD) - .create() + if (o.typeName == null && BuiltInType.isBuiltInType(o.text)) { + holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY).range(o.textRange) + .textAttributes(ProtobufHighlighter.KEYWORD).create() return } - if (o.reference?.resolve() == null) { + if (o.parent !is ProtobufTypeName && o.resolve() == null) { holder.newAnnotation( HighlightSeverity.ERROR, "Symbol '${o.text}' not found", - ) - .range(o.textRange) - .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - .withFix(AddImportFix(o)) - .create() + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) + .withFix(AddImportFix(o)).create() } + } - o.references.forEach { - if (it !is ProtobufTypeNameReference) return@forEach - val result = it.resolve() ?: return@forEach - when (result) { - is ProtobufFieldLike -> - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(it.absoluteRange) - .textAttributes(ProtobufHighlighter.FIELD) - .create() - is ProtobufMessageDefinition -> - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(it.absoluteRange) - .textAttributes(ProtobufHighlighter.MESSAGE) - .create() - is ProtobufEnumDefinition -> - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(it.absoluteRange) - .textAttributes(ProtobufHighlighter.ENUM) - .create() - else -> - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(it.absoluteRange) - .textAttributes(ProtobufHighlighter.IDENTIFIER) - .create() - } + override fun visitAnyName(o: ProtobufAnyName) { + val parentField = o.parentOfType()?.parentOfType()?.field() + + if (parentField !is ProtobufFieldDefinition || (parentField.typeName.resolve() as? ProtobufMessageDefinition)?.qualifiedName() + ?.toString() != WellknownTypes.ANY + ) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${parentField?.name()}' is not a field with Any type", + ).range(o.textRange).highlightType(ProblemHighlightType.ERROR).create() } } - override fun visitBuiltInOptionName(o: ProtobufBuiltInOptionName) { - if (o.reference?.resolve() == null) { + override fun visitOptionName(o: ProtobufOptionName) { + val target: PsiElement = o.symbolName ?: o.extensionFieldName ?: return + + if (o.resolve() == null) { + val isRoot = o.parent !is ProtobufOptionName holder.newAnnotation( HighlightSeverity.ERROR, - "Built-in option '${o.text}' not found", - ) - .range(o.textRange) - .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - .create() + "${if (isRoot) "Option" else "Field"} '${target.text}' not found", + ).range(target.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() } } - override fun visitFieldName(o: ProtobufFieldName) { - val message = o.message() ?: return - message.items { - if (it.name() == element.text) { - return - } - } - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(o.textRange) - .textAttributes(ProtobufHighlighter.FIELD) - .create() - holder.newAnnotation( - HighlightSeverity.ERROR, - "Field '${o.text}' not found", - ) - .range(o.textRange) - .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - .create() + override fun visitField(o: ProtobufField) { + visitValueAssign(o) } - override fun visitEnumValue(o: ProtobufEnumValue) { - val enum = o.enum() ?: return - enum.items { - if (it.name() == element.text) { - return - } - } - holder.newAnnotation( - HighlightSeverity.ERROR, - "Enum value '${o.text}' not found", - ) - .range(o.textRange) - .highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL) - .create() + override fun visitOptionAssign(o: ProtobufOptionAssign) { + visitValueAssign(o) } - override fun visitConstant(o: ProtobufConstant) { - val parent = - when (val parent = o.parent) { - is ProtobufArrayValue -> { - parent.parent.parent + private fun visitValueAssign(o: ValueAssign) { + val field = o.field() ?: return + val valueElement = o.valueElement() ?: return + + if (valueElement is ArrayValue) { + when (field) { + is ProtobufFieldDefinition -> { + if (!field.repeated()) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.name()}' is not a repeated field", + ).range(field.textRange).create() + } } - else -> parent - } - val field = - when (parent) { - is ProtobufOptionAssign -> { - parent.optionName.field() as? ProtobufFieldDefinition ?: return - } - is ProtobufFieldAssign -> { - parent.fieldName.reference?.resolve() as? ProtobufFieldDefinition ?: return + is ProtobufGroupDefinition -> { + if (!field.repeated()) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.name()}' is not a repeated field", + ).range(field.textRange).create() + } } - else -> return } - if (o.arrayValue != null) { - if (field.fieldLabel?.textMatches("repeated") != true) { - holder.newAnnotation( - HighlightSeverity.ERROR, - "Field \"${field.name()}\" is not a repeated value", - ) - .range(o.textRange) - .create() + valueElement.values().forEach { + checkCompatibleType(it, field) } - return + } else { + checkCompatibleType(valueElement, field) } + } - val message = - when (val type = field.typeName.text) { - BuiltInType.BOOL.value() -> - if (o.booleanValue == null) { - "Field \"${field.name()}\" required a boolean value" - } else { - null - } - BuiltInType.STRING.value() -> - if (o.stringValueList.isEmpty()) { - "Field \"${field.name()}\" required a string value" - } else { - null - } - BuiltInType.FLOAT.value(), - BuiltInType.DOUBLE.value(), - -> - if (o.numberValue?.float() == null) { - "Field \"${field.name()}\" required a number value" - } else { - null - } - BuiltInType.UINT32.value(), - BuiltInType.UINT64.value(), - BuiltInType.FIXED32.value(), - BuiltInType.FIXED64.value(), - -> - if (o.numberValue?.uint() == null) { - "Field \"${field.name()}\" required a uint value" - } else { - null - } - BuiltInType.INT32.value(), - BuiltInType.INT64.value(), - BuiltInType.SINT32.value(), - BuiltInType.SINT64.value(), - BuiltInType.SFIXED32.value(), - BuiltInType.SFIXED64.value(), - -> - if (o.numberValue?.int() == null) { - "Field \"${field.name()}\" required a int value" - } else { - null - } - else -> { - when (val typeDefinition = field.typeName.reference?.resolve()) { - is ProtobufEnumDefinition -> - if (o.enumValue == null) { - "Field \"${field.name()}\" required a value of \"${typeDefinition.qualifiedName()}\"" - } else { - null - } - is ProtobufMessageDefinition -> - if (o.messageValue == null) { - "Field \"${field.name()}\" required \"${typeDefinition.qualifiedName()}\" value" - } else { - null - } - else -> null - } - } - } - - message?.let { - holder.newAnnotation(HighlightSeverity.ERROR, it) - .range(o.textRange) - .create() + private fun checkCompatibleType( + value: ValueElement<*>, + field: ProtobufFieldLike, + ) { + val fieldType = field.fieldValueType() + val valueType = value.valueType() + if (valueType != fieldType) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${field.fieldName()}' required ${fieldType.name.lowercase()} value, but got ${valueType.name.lowercase()} value", + ).range(value.textRange).create() } } @@ -325,9 +220,17 @@ class ProtobufAnnotator : Annotator { holder.newAnnotation( HighlightSeverity.ERROR, "Enum must not be empty", - ) - .range(o.body()?.textRange ?: o.textRange) - .create() + ).range(o.body()?.textRange ?: o.textRange).create() + } + } + + private fun visitFieldLike(o: ProtobufFieldLike) { + val value = o.number() ?: return + if (value < 1) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field number must be greater than 0", + ).range(o.findChild()?.textRange ?: o.textRange).create() } } @@ -337,12 +240,13 @@ class ProtobufAnnotator : Annotator { o.owner()?.let { ScopeTracker.tracker(it).visit(o, holder) } o.parentOfType()?.let { NumberTracker.tracker(it).visit(o, holder) } visitExtendItem(o) + visitFieldLike(o) } private fun visitExtendItem(o: ProtobufElement) { if (o.parentOfType() != null) return val extendMessage = - o.parentOfType()?.typeName?.reference?.resolve() as? ProtobufMessageDefinition + o.parentOfType()?.typeName?.resolve() as? ProtobufMessageDefinition ?: return val insideExtension = @@ -355,9 +259,7 @@ class ProtobufAnnotator : Annotator { holder.newAnnotation( HighlightSeverity.ERROR, "Extend field number must defined in extension range.", - ) - .range((o as? ProtobufNumbered)?.intValue()?.textRange ?: o.textRange) - .create() + ).range((o as? ProtobufNumbered)?.intValue()?.textRange ?: o.textRange).create() } ScopeTracker.tracker(extendMessage).visit(o as? ProtobufDefinition ?: return, holder) NumberTracker.tracker(extendMessage).visit(o as? ProtobufNumbered ?: return, holder) @@ -369,6 +271,7 @@ class ProtobufAnnotator : Annotator { o.owner()?.let { ScopeTracker.tracker(it).visit(o, holder) } o.parentOfType()?.let { NumberTracker.tracker(it).visit(o, holder) } visitExtendItem(o) + visitFieldLike(o) } override fun visitMessageDefinition(o: ProtobufMessageDefinition) { @@ -389,6 +292,27 @@ class ProtobufAnnotator : Annotator { o.owner()?.let { ScopeTracker.tracker(it).visit(o, holder) } } + override fun visitEnumValue(o: ProtobufEnumValue) { + o.enum()?.items { + if (it.name() == o.text) { + return + } + } + holder.newAnnotation( + HighlightSeverity.ERROR, + "Enum value '${o.text}' not found", + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() + } + + override fun visitFieldName(o: ProtobufFieldName) { + if (o.resolve() == null) { + holder.newAnnotation( + HighlightSeverity.ERROR, + "Field '${o.text}' not existed", + ).range(o.textRange).highlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL).create() + } + } + override fun visitEnumValueDefinition(o: ProtobufEnumValueDefinition) { requireCase("Enum value name", o, CaseFormat.SCREAMING_SNAKE_CASE) @@ -400,13 +324,19 @@ class ProtobufAnnotator : Annotator { val parentName = o.owner()?.name() ?: return if (!enumName.startsWith(parentName.toScreamingSnakeCase())) { holder.newAnnotation( - HighlightSeverity.WARNING, + HighlightSeverity.WEAK_WARNING, "Value name of root enum should be start with enum name", - ) - .range(o.identifier()?.textRange ?: o.textRange) - .create() + ).range(o.identifier()?.textRange ?: o.textRange).create() } } + + val number = o.number() ?: return + if (number < 0) { + holder.newAnnotation( + HighlightSeverity.WARNING, + "Enum value number should be greater than or equal to 0", + ).range(o.integerValue?.textRange ?: o.textRange).create() + } } override fun visitReservedName(o: ProtobufReservedName) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufEditionAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufEditionAnnotator.kt new file mode 100644 index 00000000..a2086fe5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufEditionAnnotator.kt @@ -0,0 +1,17 @@ +package io.kanro.idea.plugin.protobuf.lang.annotator + +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.psi.PsiElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement + +class ProtobufEditionAnnotator : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + val file = (element as? ProtobufElement)?.file() ?: return + val syntax = file.edition() + if (syntax != null) return + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufFeature.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufFeature.kt new file mode 100644 index 00000000..570900b5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ProtobufFeature.kt @@ -0,0 +1,73 @@ +package io.kanro.idea.plugin.protobuf.lang.annotator + +data class ProtobufFeature( + val enumType: ProtobufEnumType, + val fieldPresence: ProtobufFieldPresence, + val jsonFormat: ProtobufJsonFormat, + val messageEncoding: ProtobufMessageEncoding, + val repeatedFieldEncoding: ProtobufRepeatedFieldEncoding, + val utf8Validation: ProtobufUtf8Validation, +) { + companion object { + val PROTO3 = + ProtobufFeature( + ProtobufEnumType.OPEN, + ProtobufFieldPresence.IMPLICIT, + ProtobufJsonFormat.ALLOW, + ProtobufMessageEncoding.LENGTH_PREFIXED, + ProtobufRepeatedFieldEncoding.PACKED, + ProtobufUtf8Validation.VERIFY, + ) + + val PROTO2 = + ProtobufFeature( + ProtobufEnumType.CLOSED, + ProtobufFieldPresence.EXPLICIT, + ProtobufJsonFormat.LEGACY_BEST_EFFORT, + ProtobufMessageEncoding.LENGTH_PREFIXED, + ProtobufRepeatedFieldEncoding.EXPANDED, + ProtobufUtf8Validation.NONE, + ) + + val EDITION_2023 = + ProtobufFeature( + ProtobufEnumType.OPEN, + ProtobufFieldPresence.EXPLICIT, + ProtobufJsonFormat.ALLOW, + ProtobufMessageEncoding.LENGTH_PREFIXED, + ProtobufRepeatedFieldEncoding.PACKED, + ProtobufUtf8Validation.VERIFY, + ) + } +} + +enum class ProtobufEnumType { + CLOSED, + OPEN, +} + +enum class ProtobufFieldPresence { + LEGACY_REQUIRED, + EXPLICIT, + IMPLICIT, +} + +enum class ProtobufJsonFormat { + ALLOW, + LEGACY_BEST_EFFORT, +} + +enum class ProtobufMessageEncoding { + LENGTH_PREFIXED, + DELIMITED, +} + +enum class ProtobufRepeatedFieldEncoding { + PACKED, + EXPANDED, +} + +enum class ProtobufUtf8Validation { + VERIFY, + NONE, +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ScopeTracker.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ScopeTracker.kt index dbff337d..220ce3e8 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ScopeTracker.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/annotator/ScopeTracker.kt @@ -5,12 +5,13 @@ import com.intellij.lang.annotation.HighlightSeverity import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedName import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufMultiNameDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.name +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem open class ScopeTracker(scope: ProtobufScope) { private val nameMap = mutableMapOf>() @@ -37,7 +38,7 @@ open class ScopeTracker(scope: ProtobufScope) { } protected open fun record(reserved: ProtobufReservedName) { - val name = reserved.identifierLiteral?.text ?: return + val name = reserved.name() reservedNameMap.getOrPut(name) { mutableListOf() }.add(reserved) @@ -55,7 +56,7 @@ open class ScopeTracker(scope: ProtobufScope) { reserved: ProtobufReservedName, holder: AnnotationHolder, ) { - val name = reserved.identifierLiteral?.text ?: return + val name = reserved.name() createError(reserved, buildMessage(name, reserved) ?: return, holder) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/AddImportInsertHandler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/AddImportInsertHandler.kt index f3acb32b..edeac507 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/AddImportInsertHandler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/AddImportInsertHandler.kt @@ -4,8 +4,8 @@ import com.intellij.codeInsight.completion.InsertHandler import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement import com.intellij.psi.PsiDocumentManager -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile class AddImportInsertHandler(private val element: ProtobufElement) : InsertHandler { override fun handleInsert( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/EnumValueNameProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/EnumValueNameProvider.kt index 416a45ed..27163fcd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/EnumValueNameProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/EnumValueNameProvider.kt @@ -8,7 +8,7 @@ import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.psi.util.parentOfType import com.intellij.util.ProcessingContext -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition import io.kanro.idea.plugin.protobuf.string.toScreamingSnakeCase object EnumValueNameProvider : CompletionProvider() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/FieldNameProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/FieldNameProvider.kt index f30bc40b..88132d79 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/FieldNameProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/FieldNameProvider.kt @@ -10,11 +10,11 @@ import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiElement import com.intellij.psi.util.parentOfType import com.intellij.util.ProcessingContext -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedStatement import io.kanro.idea.plugin.protobuf.lang.psi.forEachPrev -import io.kanro.idea.plugin.protobuf.lang.psi.range +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.range import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType import io.kanro.idea.plugin.protobuf.string.case.CommonWordSplitter import io.kanro.idea.plugin.protobuf.string.case.SnakeCaseFormatter @@ -29,7 +29,7 @@ object FieldNameProvider : CompletionProvider() { ) { val element = parameters.position val field = element.parentOfType() ?: return - val type = field.typeName.symbolNameList.lastOrNull()?.text ?: return + val type = field.typeName.leaf()?.text ?: return val searchName = element.text.substringBeforeLast("_IntellijIdeaRulezzz", "") val prevNumber = prevFieldNumber(element) val inserter = fieldNumberInserter(prevNumber + 1) @@ -73,7 +73,8 @@ object FieldNameProvider : CompletionProvider() { is ProtobufReservedStatement -> return it.reservedRangeList.maxOf { it.range()?.last?.takeIf { it != Long.MAX_VALUE } ?: 0 }.takeIf { it != 0L } ?: return@forEachPrev - is ProtobufExtensionStatement -> return it.reservedRangeList.maxOf { + + is ProtobufExtensionStatement -> return it.extensionRangeList.maxOf { it.range()?.last?.takeIf { it != Long.MAX_VALUE } ?: 0 }.takeIf { it != 0L } ?: return@forEachPrev } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/ProtobufCompletionContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/ProtobufCompletionContributor.kt index 413ebe46..757c0348 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/ProtobufCompletionContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/completion/ProtobufCompletionContributor.kt @@ -4,16 +4,16 @@ import com.intellij.codeInsight.completion.CompletionContributor import com.intellij.codeInsight.completion.CompletionType import com.intellij.patterns.PlatformPatterns import com.intellij.psi.PsiErrorElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSyntaxStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufSyntaxStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName class ProtobufCompletionContributor : CompletionContributor() { init { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/MarkdownSymbolReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/MarkdownSymbolReference.kt index f0f009c0..6db2ec5c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/MarkdownSymbolReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/MarkdownSymbolReference.kt @@ -16,12 +16,11 @@ import com.intellij.psi.util.parentOfType import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver import io.kanro.idea.plugin.protobuf.lang.util.AnyElement @@ -122,7 +121,7 @@ class MarkdownSymbolReference(element: MarkdownShortReferenceLink) : element: ProtobufElement, scope: QualifiedName, ): LookupElement? { - if (element !is ProtobufLookupItem) return null + if (element !is io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement) return null return if (element is ProtobufPackageName) { element.lookup()?.withLookupString(scope.append(element.name).toString()) ?.withInsertHandler(packageInsertHandler) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/ProtobufLineCommentsMarkdownInjector.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/ProtobufLineCommentsMarkdownInjector.kt index ff76a08e..ae88d3ed 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/ProtobufLineCommentsMarkdownInjector.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/docs/ProtobufLineCommentsMarkdownInjector.kt @@ -3,7 +3,7 @@ package io.kanro.idea.plugin.protobuf.lang.docs import com.intellij.lang.injection.MultiHostInjector import com.intellij.lang.injection.MultiHostRegistrar import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufLineCommentImpl import io.kanro.idea.plugin.protobuf.string.lineCommentRanges import org.intellij.plugins.markdown.lang.MarkdownLanguage diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextPairedBraceMatcher.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextPairedBraceMatcher.kt new file mode 100644 index 00000000..0fec7bb8 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextPairedBraceMatcher.kt @@ -0,0 +1,37 @@ +package io.kanro.idea.plugin.protobuf.lang.edting + +import com.intellij.lang.BracePair +import com.intellij.lang.PairedBraceMatcher +import com.intellij.psi.PsiFile +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextPairedBraceMatcher : PairedBraceMatcher { + override fun getPairs(): Array { + return Companion.pairs + } + + override fun isPairedBracesAllowedBeforeType( + lbraceType: IElementType, + contextType: IElementType?, + ): Boolean { + return true + } + + override fun getCodeConstructStart( + file: PsiFile?, + openingBraceOffset: Int, + ): Int { + return 0 + } + + companion object { + private val pairs = + arrayOf( + BracePair(ProtoTextTokens.LBRACE, ProtoTextTokens.RBRACE, false), + BracePair(ProtoTextTokens.LBRACK, ProtoTextTokens.RBRACK, false), + BracePair(ProtoTextTokens.LPAREN, ProtoTextTokens.RPAREN, false), + BracePair(ProtoTextTokens.LT, ProtoTextTokens.GT, false), + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextQuoteHandler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextQuoteHandler.kt new file mode 100644 index 00000000..d69fdf1e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextQuoteHandler.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.edting + +import com.intellij.codeInsight.editorActions.SimpleTokenSetQuoteHandler +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextQuoteHandler : SimpleTokenSetQuoteHandler(ProtoTextTokens.STRING_LITERAL) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextSpellcheckingStrategy.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextSpellcheckingStrategy.kt new file mode 100644 index 00000000..fc2e77f9 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtoTextSpellcheckingStrategy.kt @@ -0,0 +1,21 @@ +package io.kanro.idea.plugin.protobuf.lang.edting + +import com.intellij.psi.PsiElement +import com.intellij.spellchecker.inspections.PlainTextSplitter +import com.intellij.spellchecker.tokenizer.SpellcheckingStrategy +import com.intellij.spellchecker.tokenizer.Tokenizer +import com.intellij.spellchecker.tokenizer.TokenizerBase +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextStringValue + +class ProtoTextSpellcheckingStrategy : SpellcheckingStrategy() { + override fun getTokenizer(element: PsiElement?): Tokenizer<*> { + if (element is ProtoTextStringValue) { + return plainTextTokenizer + } + return super.getTokenizer(element) + } + + companion object { + private val plainTextTokenizer = TokenizerBase.create(PlainTextSplitter.getInstance()) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufPairedBraceMatcher.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufPairedBraceMatcher.kt index 94b37320..5385874e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufPairedBraceMatcher.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufPairedBraceMatcher.kt @@ -4,7 +4,7 @@ import com.intellij.lang.BracePair import com.intellij.lang.PairedBraceMatcher import com.intellij.psi.PsiFile import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufPairedBraceMatcher : PairedBraceMatcher { override fun getPairs(): Array { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufQuoteHandler.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufQuoteHandler.kt index 185584b7..dcbc1864 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufQuoteHandler.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufQuoteHandler.kt @@ -1,6 +1,6 @@ package io.kanro.idea.plugin.protobuf.lang.edting import com.intellij.codeInsight.editorActions.SimpleTokenSetQuoteHandler -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufQuoteHandler : SimpleTokenSetQuoteHandler(ProtobufTokens.STRING_LITERAL) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufSpellcheckingStrategy.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufSpellcheckingStrategy.kt index 9056a656..7864e418 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufSpellcheckingStrategy.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/edting/ProtobufSpellcheckingStrategy.kt @@ -5,7 +5,7 @@ import com.intellij.spellchecker.inspections.PlainTextSplitter import com.intellij.spellchecker.tokenizer.SpellcheckingStrategy import com.intellij.spellchecker.tokenizer.Tokenizer import com.intellij.spellchecker.tokenizer.TokenizerBase -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue class ProtobufSpellcheckingStrategy : SpellcheckingStrategy() { override fun getTokenizer(element: PsiElement?): Tokenizer<*> { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/folding/ProtobufFoldingBuilder.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/folding/ProtobufFoldingBuilder.kt index 9f1a5a3b..b4a33ebb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/folding/ProtobufFoldingBuilder.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/folding/ProtobufFoldingBuilder.kt @@ -11,10 +11,9 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.PsiWhiteSpace -import com.intellij.refactoring.suggested.startOffset -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFolding +import io.kanro.idea.plugin.protobuf.lang.psi.feature.FoldingElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren import java.util.Stack @@ -28,7 +27,7 @@ class ProtobufFoldingBuilder : FoldingBuilderEx(), DumbAware { val file = (root.containingFile as? ProtobufFile) ?: return arrayOf() result += buildFoldingDescriptorForFile(file) - root.walkChildren { + root.walkChildren { it.folding()?.let { result += it } } return result.toTypedArray() @@ -54,6 +53,7 @@ class ProtobufFoldingBuilder : FoldingBuilderEx(), DumbAware { is PsiComment, -> { } + else -> { if (stack.size >= 2) { val start = stack.firstElement() @@ -61,8 +61,8 @@ class ProtobufFoldingBuilder : FoldingBuilderEx(), DumbAware { stack.clear() val range = TextRange.create( - start.stringValue?.startOffset ?: return@forEach, - end.startOffset + end.textLength, + start.stringValue?.textRange?.startOffset ?: return@forEach, + end.textRange.startOffset + end.textLength, ) result += diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextCommenter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextCommenter.kt new file mode 100644 index 00000000..0c2557aa --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextCommenter.kt @@ -0,0 +1,61 @@ +package io.kanro.idea.plugin.protobuf.lang.formatter + +import com.intellij.lang.CodeDocumentationAwareCommenterEx +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiElement +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextCommenter : CodeDocumentationAwareCommenterEx { + override fun getBlockCommentPrefix(): String? { + return null + } + + override fun getBlockCommentSuffix(): String? { + return null + } + + override fun getLineCommentPrefix(): String { + return "#" + } + + override fun getCommentedBlockCommentPrefix(): String? { + return null + } + + override fun getCommentedBlockCommentSuffix(): String? { + return null + } + + override fun getLineCommentTokenType(): IElementType { + return ProtoTextTokens.SHARP_LINE_COMMENT + } + + override fun getBlockCommentTokenType(): IElementType? { + return null + } + + override fun getDocumentationCommentTokenType(): IElementType? { + return null + } + + override fun getDocumentationCommentPrefix(): String? { + return null + } + + override fun getDocumentationCommentLinePrefix(): String? { + return null + } + + override fun getDocumentationCommentSuffix(): String? { + return null + } + + override fun isDocumentationComment(element: PsiComment?): Boolean { + return false + } + + override fun isDocumentationCommentText(element: PsiElement?): Boolean { + return false + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextFormattingModelBuilder.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextFormattingModelBuilder.kt new file mode 100644 index 00000000..6ab44735 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextFormattingModelBuilder.kt @@ -0,0 +1,60 @@ +package io.kanro.idea.plugin.protobuf.lang.formatter + +import com.intellij.formatting.FormattingContext +import com.intellij.formatting.FormattingModel +import com.intellij.formatting.FormattingModelBuilder +import com.intellij.formatting.SpacingBuilder +import com.intellij.formatting.Wrap +import com.intellij.formatting.WrapType +import com.intellij.psi.codeStyle.CodeStyleSettings +import com.intellij.psi.codeStyle.CommonCodeStyleSettings +import com.intellij.psi.formatter.FormattingDocumentModelImpl +import com.intellij.psi.formatter.PsiBasedFormattingModel +import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextFormattingModelBuilder : FormattingModelBuilder { + override fun createModel(formattingContext: FormattingContext): FormattingModel { + val file = formattingContext.containingFile + return PsiBasedFormattingModel( + file, + ProtobufBlock( + BlockType.BODY, + formattingContext.node, + Wrap.createWrap(WrapType.NONE, false), + null, + spacingBuilder(formattingContext.codeStyleSettings), + ), + FormattingDocumentModelImpl.createOn(file), + ) + } + + companion object { + private fun spacingBuilder(settings: CodeStyleSettings): SpacingBuilder { + val commonSettings: CommonCodeStyleSettings = settings.getCommonSettings(ProtobufLanguage) + return SpacingBuilder(commonSettings) + .before(ProtoTextTokens.SEMI) + .none() + .around(ProtoTextTokens.ASSIGN) + .spaces(1) + .after(ProtoTextTokens.COMMA) + .spaces(1) + .withinPair(ProtoTextTokens.LBRACE, ProtoTextTokens.RBRACE) + .spaceIf(commonSettings.SPACE_WITHIN_BRACES, false) + .withinPair(ProtoTextTokens.LBRACK, ProtoTextTokens.RBRACK) + .spaceIf(commonSettings.SPACE_WITHIN_BRACKETS, false) + .withinPair(ProtoTextTokens.LPAREN, ProtoTextTokens.RPAREN) + .spaceIf(commonSettings.SPACE_WITHIN_PARENTHESES, false) + .before(ProtoTextTokens.COMMA) + .spaceIf(commonSettings.SPACE_BEFORE_COMMA) + .after(ProtoTextTokens.COMMA) + .spaceIf(commonSettings.SPACE_AFTER_COMMA) + .around(ProtoTextTokens.ASSIGN) + .spaceIf(commonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS) + .before(ProtoTextTokens.COLON) + .spaceIf(commonSettings.SPACE_BEFORE_COLON) + .after(ProtoTextTokens.COLON) + .spaceIf(commonSettings.SPACE_AFTER_COLON) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextLanguageCodeStyleSettingsProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextLanguageCodeStyleSettingsProvider.kt new file mode 100644 index 00000000..7a7bca4d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtoTextLanguageCodeStyleSettingsProvider.kt @@ -0,0 +1,112 @@ +package io.kanro.idea.plugin.protobuf.lang.formatter + +import com.intellij.application.options.IndentOptionsEditor +import com.intellij.application.options.SmartIndentOptionsEditor +import com.intellij.lang.Language +import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizable +import com.intellij.psi.codeStyle.CodeStyleSettingsCustomizableOptions +import com.intellij.psi.codeStyle.CommonCodeStyleSettings +import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +class ProtoTextLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvider() { + override fun getLanguage(): Language { + return ProtoTextLanguage + } + + override fun getIndentOptionsEditor(): IndentOptionsEditor { + return SmartIndentOptionsEditor() + } + + override fun getCodeSample(settingsType: SettingsType): String { + return """# This is an example of Protocol Buffer's text format. +# Unlike .proto files, only shell-style line comments are supported. + +name: "John Smith" + +pet { + kind: DOG + name: "Fluffy" + tail_wagginess: 0.65f +} + +pet < + kind: LIZARD + name: "Lizzy" + legs: 4 +> + +string_value_with_escape: "valid \n escape" +repeated_values: [ "one", "two", "three" ]""" + } + + override fun customizeDefaults( + commonSettings: CommonCodeStyleSettings, + indentOptions: CommonCodeStyleSettings.IndentOptions, + ) { + commonSettings.SPACE_BEFORE_COLON = false + commonSettings.KEEP_BLANK_LINES_BETWEEN_PACKAGE_DECLARATION_AND_HEADER = 1 + } + + override fun customizeSettings( + consumer: CodeStyleSettingsCustomizable, + settingsType: SettingsType, + ) { + when (settingsType) { + SettingsType.SPACING_SETTINGS -> { + consumer.showStandardOptions("SPACE_WITHIN_BRACES") + consumer.showStandardOptions("SPACE_WITHIN_BRACKETS") + consumer.showStandardOptions("SPACE_WITHIN_PARENTHESES") + consumer.showStandardOptions("SPACE_BEFORE_COMMA") + consumer.showStandardOptions("SPACE_AFTER_COMMA") + consumer.showStandardOptions("SPACE_BEFORE_COLON") + consumer.moveStandardOption("SPACE_BEFORE_COLON", "Assignment") + consumer.showStandardOptions("SPACE_AFTER_COLON") + consumer.moveStandardOption("SPACE_AFTER_COLON", "Assignment") + consumer.showStandardOptions("SPACE_AROUND_ASSIGNMENT_OPERATORS") + consumer.renameStandardOption("SPACE_AROUND_ASSIGNMENT_OPERATORS", "Around '='") + consumer.moveStandardOption("SPACE_AROUND_ASSIGNMENT_OPERATORS", "Assignment") + consumer.showStandardOptions("SPACE_BEFORE_CLASS_LBRACE") + consumer.renameStandardOption("SPACE_BEFORE_CLASS_LBRACE", "Body left brace") + consumer.moveStandardOption("SPACE_BEFORE_CLASS_LBRACE", "Before block") + consumer.showStandardOptions("SPACE_BEFORE_METHOD_LBRACE") + consumer.renameStandardOption("SPACE_BEFORE_METHOD_LBRACE", "Option left bracket") + consumer.moveStandardOption("SPACE_BEFORE_METHOD_LBRACE", "Before block") + } + + SettingsType.BLANK_LINES_SETTINGS -> { + val blankLines = CodeStyleSettingsCustomizableOptions.getInstance().BLANK_LINES + consumer.showCustomOption( + ProtobufCodeStyleSettings::class.java, + ProtobufCodeStyleSettings::BLANK_LINES_AFTER_SYNTAX.name, + "After syntax statement", + blankLines, + ) + consumer.showStandardOptions("BLANK_LINES_AFTER_PACKAGE") + consumer.showStandardOptions("BLANK_LINES_AFTER_IMPORTS") + consumer.showCustomOption( + ProtobufCodeStyleSettings::class.java, + ProtobufCodeStyleSettings::BLANK_LINES_AFTER_FILE_OPTIONS.name, + "After file options", + blankLines, + ) + + val blankLinesKeep = CodeStyleSettingsCustomizableOptions.getInstance().BLANK_LINES_KEEP + consumer.showCustomOption( + ProtobufCodeStyleSettings::class.java, + ProtobufCodeStyleSettings::KEEP_BLANK_LINES_BETWEEN_IMPORTS.name, + "Between imports", + blankLinesKeep, + ) + consumer.showCustomOption( + ProtobufCodeStyleSettings::class.java, + ProtobufCodeStyleSettings::KEEP_BLANK_LINES_BETWEEN_FILE_OPTIONS.name, + "Between file options", + blankLinesKeep, + ) + } + + else -> {} + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufBlock.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufBlock.kt index 4023d269..d9361167 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufBlock.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufBlock.kt @@ -7,13 +7,15 @@ import com.intellij.formatting.Spacing import com.intellij.formatting.SpacingBuilder import com.intellij.formatting.Wrap import com.intellij.lang.ASTNode +import com.intellij.psi.PsiFile import com.intellij.psi.TokenType import com.intellij.psi.formatter.common.AbstractBlock -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufBlock -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.type.ProtobufStatement -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufCommentToken -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufCommentToken +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextCommentToken +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens +import io.kanro.idea.plugin.protobuf.lang.psi.type.BlockElement +import io.kanro.idea.plugin.protobuf.lang.psi.type.StatementElement enum class BlockType { BODY, @@ -46,13 +48,12 @@ class ProtobufBlock( override fun getIndent(): Indent { return when (type) { BlockType.BODY -> Indent.getNoneIndent() - BlockType.STATEMENT -> { - if (node.treeParent.psi is ProtobufFile) { - Indent.getNoneIndent() - } else { - Indent.getNormalIndent() + BlockType.STATEMENT -> + when (node.treeParent.psi) { + is PsiFile -> Indent.getNoneIndent() + else -> Indent.getNormalIndent() } - } + BlockType.FRAGMENT -> { if (node.treePrev == null) return Indent.getNoneIndent() when (node.elementType) { @@ -66,7 +67,18 @@ class ProtobufBlock( ProtobufTokens.RBRACK, ProtobufTokens.LT, ProtobufTokens.GT, + ProtoTextTokens.SEMI, + ProtoTextTokens.COMMA, + ProtoTextTokens.LBRACE, + ProtoTextTokens.RBRACE, + ProtoTextTokens.LPAREN, + ProtoTextTokens.RPAREN, + ProtoTextTokens.LBRACK, + ProtoTextTokens.RBRACK, + ProtoTextTokens.LT, + ProtoTextTokens.GT, -> Indent.getNoneIndent() + else -> Indent.getContinuationWithoutFirstIndent() } } @@ -76,14 +88,20 @@ class ProtobufBlock( override fun getChildIndent(): Indent? { return when (type) { BlockType.BODY -> { - if (node.psi is ProtobufFile) { - Indent.getNoneIndent() - } else { - Indent.getNormalIndent() + when (node.psi) { + is PsiFile -> Indent.getNoneIndent() + + else -> Indent.getNormalIndent() } } - BlockType.STATEMENT -> Indent.getContinuationWithoutFirstIndent() - BlockType.FRAGMENT -> Indent.getContinuationWithoutFirstIndent() + + BlockType.STATEMENT -> { + Indent.getContinuationWithoutFirstIndent() + } + + BlockType.FRAGMENT -> { + Indent.getContinuationWithoutFirstIndent() + } } } @@ -103,15 +121,18 @@ class ProtobufBlock( private fun buildChild(child: ASTNode): Block { val psi = child.psi - if (psi is ProtobufBlock) { + if (psi is BlockElement) { return ProtobufBlock(BlockType.BODY, child, wrap, alignment, spacingBuilder) } - if (psi is ProtobufStatement) { + if (psi is StatementElement) { return ProtobufBlock(BlockType.STATEMENT, child, wrap, alignment, spacingBuilder) } if (child.elementType is ProtobufCommentToken) { return ProtobufBlock(BlockType.STATEMENT, child, wrap, alignment, spacingBuilder) } + if (child.elementType is ProtoTextCommentToken) { + return ProtobufBlock(BlockType.STATEMENT, child, wrap, alignment, spacingBuilder) + } return ProtobufBlock(BlockType.FRAGMENT, child, wrap, alignment, spacingBuilder) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufCommenter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufCommenter.kt index 58596afd..c30a6f9f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufCommenter.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufCommenter.kt @@ -4,7 +4,7 @@ import com.intellij.lang.CodeDocumentationAwareCommenterEx import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufCommenter : CodeDocumentationAwareCommenterEx { override fun getBlockCommentPrefix(): String { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufFormattingModelBuilder.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufFormattingModelBuilder.kt index a44e7bae..09ef3423 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufFormattingModelBuilder.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufFormattingModelBuilder.kt @@ -10,9 +10,10 @@ import com.intellij.psi.codeStyle.CodeStyleSettings import com.intellij.psi.codeStyle.CommonCodeStyleSettings import com.intellij.psi.formatter.FormattingDocumentModelImpl import com.intellij.psi.formatter.PsiBasedFormattingModel +import com.intellij.psi.tree.TokenSet import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypes -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypes +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufFormattingModelBuilder : FormattingModelBuilder { override fun createModel(formattingContext: FormattingContext): FormattingModel { @@ -75,7 +76,7 @@ class ProtobufFormattingModelBuilder : FormattingModelBuilder { .spacing(0, 0, 1, true, customSettings.KEEP_BLANK_LINES_BETWEEN_IMPORTS) .between(ProtobufTypes.FILE_OPTION, ProtobufTypes.FILE_OPTION) .spacing(0, 0, 1, true, customSettings.KEEP_BLANK_LINES_BETWEEN_FILE_OPTIONS) - .after(ProtobufTypes.SYNTAX_STATEMENT) + .after(TokenSet.create(ProtobufTypes.SYNTAX_STATEMENT, ProtobufTypes.EDITION_STATEMENT)) .blankLines(customSettings.BLANK_LINES_AFTER_SYNTAX) .after(ProtobufTypes.PACKAGE_STATEMENT) .blankLines(commonSettings.BLANK_LINES_AFTER_PACKAGE) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufImportOptimizer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufImportOptimizer.kt index d2d29cc7..e4bd2ade 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufImportOptimizer.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufImportOptimizer.kt @@ -3,13 +3,12 @@ package io.kanro.idea.plugin.protobuf.lang.formatter import com.intellij.lang.ImportOptimizer import com.intellij.psi.PsiFile import io.kanro.idea.plugin.protobuf.lang.annotator.FileTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSyntaxStatement import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.resolve -import io.kanro.idea.plugin.protobuf.lang.psi.value -import io.kanro.idea.plugin.protobuf.lang.util.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufSyntaxStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve class ProtobufImportOptimizer : ImportOptimizer { override fun supports(file: PsiFile): Boolean { @@ -18,49 +17,47 @@ class ProtobufImportOptimizer : ImportOptimizer { override fun processFile(file: PsiFile): Runnable { return Runnable { - ProtobufImportOptimizer.processFile(file) + optimizeImportProtobufFile(file) } } +} - companion object { - fun processFile(file: PsiFile) { - if (file !is ProtobufFile) return - val imports = file.imports() - if (imports.count() == 0) return - val tracker = FileTracker.tracker(file) - val optimizedImports = - imports.mapNotNull { - val resolved = it.resolve() ?: return@mapNotNull it - if (tracker.isUnused(resolved)) { - null - } else { - it - } - }.sortedBy { - it.stringValue?.value() ?: "" - }.joinToString("\n") { - it.text - } - - imports.forEach { - it.delete() +fun optimizeImportProtobufFile(file: PsiFile) { + if (file !is ProtobufFile) return + val imports = file.imports().toList() + if (imports.isEmpty()) return + val tracker = FileTracker.tracker(file) + val optimizedImports = + imports.mapNotNull { + val resolved = it.resolve() ?: return@mapNotNull it + if (tracker.isUnused(resolved)) { + null + } else { + it } + }.sortedBy { + it.stringValue?.value() ?: "" + }.joinToString("\n") { + it.text + } - file.findChild()?.let { - val tempFile = ProtobufPsiFactory.createFile(file.project, "\n\n$optimizedImports") - file.addRangeAfter(tempFile.firstChild, tempFile.lastChild, it) - return - } + imports.forEach { + it.delete() + } - file.findChild()?.let { - val tempFile = ProtobufPsiFactory.createFile(file.project, "\n\n$optimizedImports") - file.addRangeAfter(tempFile.firstChild, tempFile.lastChild, it) - return - } + file.findChild()?.let { + val tempFile = ProtobufPsiFactory.createFile(file.project, "\n\n$optimizedImports") + file.addRangeAfter(tempFile.firstChild, tempFile.lastChild, it) + return + } - val tempFile = ProtobufPsiFactory.createFile(file.project, "$optimizedImports\n\n") - file.addRangeBefore(tempFile.firstChild, tempFile.lastChild, file.firstChild) - return - } + file.findChild()?.let { + val tempFile = ProtobufPsiFactory.createFile(file.project, "\n\n$optimizedImports") + file.addRangeAfter(tempFile.firstChild, tempFile.lastChild, it) + return } + + val tempFile = ProtobufPsiFactory.createFile(file.project, "$optimizedImports\n\n") + file.addRangeBefore(tempFile.firstChild, tempFile.lastChild, file.firstChild) + return } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufLanguageCodeStyleSettingsProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufLanguageCodeStyleSettingsProvider.kt index 51946522..b44b975b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufLanguageCodeStyleSettingsProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/formatter/ProtobufLanguageCodeStyleSettingsProvider.kt @@ -103,6 +103,7 @@ message GetMessageRequest { consumer.renameStandardOption("SPACE_BEFORE_METHOD_LBRACE", "Option left bracket") consumer.moveStandardOption("SPACE_BEFORE_METHOD_LBRACE", "Before block") } + SettingsType.BLANK_LINES_SETTINGS -> { val blankLines = CodeStyleSettingsCustomizableOptions.getInstance().BLANK_LINES consumer.showCustomOption( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightingAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightingAnnotator.kt deleted file mode 100644 index d0734277..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightingAnnotator.kt +++ /dev/null @@ -1,90 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.highligh - -import com.intellij.codeInsight.daemon.impl.HighlightInfoType -import com.intellij.lang.annotation.AnnotationHolder -import com.intellij.lang.annotation.Annotator -import com.intellij.openapi.editor.colors.TextAttributesKey -import com.intellij.psi.PsiComment -import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufNumberValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufVisitor -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocument - -class ProtobufHighlightingAnnotator : Annotator { - override fun annotate( - element: PsiElement, - holder: AnnotationHolder, - ) { - element.accept(ProtobufHighlightingVisitor(holder)) - } - - private class ProtobufHighlightingVisitor(val holder: AnnotationHolder) : ProtobufVisitor() { - override fun visitEnumValueDefinition(o: ProtobufEnumValueDefinition) { - createHighlight(o.identifier() ?: return, ProtobufHighlighter.ENUM_VALUE) - } - - override fun visitEnumValue(o: ProtobufEnumValue) { - createHighlight(o, ProtobufHighlighter.ENUM_VALUE) - } - - override fun visitNumberValue(o: ProtobufNumberValue) { - if (o.floatLiteral == null && o.integerLiteral == null) { - createHighlight(o, ProtobufHighlighter.KEYWORD) - } - } - - override fun visitPackageName(o: ProtobufPackageName) { - createHighlight(o, ProtobufHighlighter.IDENTIFIER) - } - - override fun visitIdentifier(o: ProtobufIdentifier) { - when (o.parent) { - is ProtobufMessageDefinition -> createHighlight(o, ProtobufHighlighter.MESSAGE) - is ProtobufFieldDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) - is ProtobufMapFieldDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) - is ProtobufOneofDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) - is ProtobufGroupDefinition -> createHighlight(o, ProtobufHighlighter.MESSAGE) - is ProtobufFieldAssign -> createHighlight(o, ProtobufHighlighter.FIELD) - is ProtobufEnumDefinition -> createHighlight(o, ProtobufHighlighter.ENUM) - is ProtobufServiceDefinition -> createHighlight(o, ProtobufHighlighter.SERVICE) - is ProtobufRpcDefinition -> createHighlight(o, ProtobufHighlighter.METHOD) - } - } - - override fun visitFieldName(o: ProtobufFieldName) { - createHighlight(o, ProtobufHighlighter.IDENTIFIER) - } - - override fun visitComment(comment: PsiComment) { - if (comment is ProtobufDocument) { - if (comment.owner != null) { - createHighlight(comment, ProtobufHighlighter.DOC_COMMENT) - } - } - } - - private fun createHighlight( - element: PsiElement, - textAttributesKey: TextAttributesKey, - ) { - holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) - .range(element.textRange) - .textAttributes(textAttributesKey) - .create() - } - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextColorSettingsPage.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextColorSettingsPage.kt new file mode 100644 index 00000000..465deec4 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextColorSettingsPage.kt @@ -0,0 +1,80 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.fileTypes.SyntaxHighlighter +import com.intellij.openapi.options.colors.AttributesDescriptor +import com.intellij.openapi.options.colors.ColorDescriptor +import com.intellij.openapi.options.colors.ColorSettingsPage +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import javax.swing.Icon + +class ProtoTextColorSettingsPage : ColorSettingsPage { + override fun getAttributeDescriptors(): Array { + return DESCRIPTORS + } + + override fun getColorDescriptors(): Array { + return ColorDescriptor.EMPTY_ARRAY + } + + override fun getDisplayName(): String { + return "ProtoText" + } + + override fun getIcon(): Icon { + return ProtobufIcons.TEXT_FILE + } + + override fun getHighlighter(): SyntaxHighlighter { + return ProtoTextHighlighter() + } + + override fun getDemoText(): String { + return """ + # proto-file: google/protobuf/unittest_custom_options.proto + # proto-message: Aggregate + + s: 'FileAnnotation' + i: 100 + sub { s: 'NestedFileAnnotation' } + file { + [protobuf_unittest.fileopt] { s: 'FileExtensionAnnotation' } + } + mset { + [protobuf_unittest.AggregateMessageSetElement.message_set_extension] { + s: 'EmbeddedMessageSetElement' + } + } + any { + [type.googleapis.com/protobuf_unittest.AggregateMessageSetElement] { + s: 'EmbeddedMessageSetElement' + } + } + """.trimIndent() + } + + override fun getAdditionalHighlightingTagToDescriptorMap(): MutableMap? { + return mutableMapOf() + } + + companion object { + val DESCRIPTORS = + arrayOf( + AttributesDescriptor("Braces and Operators//Braces", ProtoTextHighlighter.BRACES), + AttributesDescriptor("Braces and Operators//Brackets", ProtoTextHighlighter.BRACKETS), + AttributesDescriptor("Braces and Operators//Comma", ProtoTextHighlighter.COMMA), + AttributesDescriptor("Braces and Operators//Dot", ProtoTextHighlighter.DOT), + AttributesDescriptor("Braces and Operators//Operator sign", ProtoTextHighlighter.OPERATION_SIGN), + AttributesDescriptor("Braces and Operators//Parentheses", ProtoTextHighlighter.PARENTHESES), + AttributesDescriptor("Braces and Operators//Semicolon", ProtoTextHighlighter.SEMICOLON), + AttributesDescriptor("Comments//Block comment", ProtoTextHighlighter.BLOCK_COMMENT), + AttributesDescriptor("Comments//Line comment", ProtoTextHighlighter.LINE_COMMENT), + AttributesDescriptor("Identifiers//Default", ProtoTextHighlighter.IDENTIFIER), + AttributesDescriptor("Identifiers//Field", ProtoTextHighlighter.FIELD), + AttributesDescriptor("Identifiers//Enum value", ProtoTextHighlighter.ENUM_VALUE), + AttributesDescriptor("Keyword", ProtoTextHighlighter.KEYWORD), + AttributesDescriptor("Number", ProtoTextHighlighter.NUMBER), + AttributesDescriptor("String", ProtoTextHighlighter.STRING), + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlighter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlighter.kt new file mode 100644 index 00000000..a23a90e0 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlighter.kt @@ -0,0 +1,122 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.lexer.Lexer +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors +import com.intellij.openapi.editor.HighlighterColors +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.fileTypes.SyntaxHighlighterBase +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.lexer.ProtoTextLexer +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextHighlighter : SyntaxHighlighterBase() { + override fun getHighlightingLexer(): Lexer { + return ProtoTextLexer() + } + + override fun getTokenHighlights(tokenType: IElementType): Array { + return pack(attributesMap[tokenType]) + } + + companion object { + val IDENTIFIER = + TextAttributesKey.createTextAttributesKey( + "TXTPB_IDENTIFIER", + DefaultLanguageHighlighterColors.IDENTIFIER, + ) + val FIELD = + TextAttributesKey.createTextAttributesKey( + "TXTPB_FIELD", + DefaultLanguageHighlighterColors.INSTANCE_FIELD, + ) + val NUMBER = + TextAttributesKey.createTextAttributesKey( + "TXTPB_NUMBER", + DefaultLanguageHighlighterColors.NUMBER, + ) + val KEYWORD = + TextAttributesKey.createTextAttributesKey( + "TXTPB_KEYWORD", + DefaultLanguageHighlighterColors.KEYWORD, + ) + val STRING = + TextAttributesKey.createTextAttributesKey( + "TXTPB_STRING", + DefaultLanguageHighlighterColors.STRING, + ) + val ENUM_VALUE = + TextAttributesKey.createTextAttributesKey( + "TXTPB_ENUM_VALUE", + DefaultLanguageHighlighterColors.CONSTANT, + ) + val BLOCK_COMMENT = + TextAttributesKey.createTextAttributesKey( + "TXTPB_BLOCK_COMMENT", + DefaultLanguageHighlighterColors.BLOCK_COMMENT, + ) + val LINE_COMMENT = + TextAttributesKey.createTextAttributesKey( + "TXTPB_LINE_COMMENT", + DefaultLanguageHighlighterColors.LINE_COMMENT, + ) + val OPERATION_SIGN = + TextAttributesKey.createTextAttributesKey( + "TXTPB_OPERATION_SIGN", + DefaultLanguageHighlighterColors.OPERATION_SIGN, + ) + val BRACES = + TextAttributesKey.createTextAttributesKey( + "TXTPB_BRACES", + DefaultLanguageHighlighterColors.BRACES, + ) + val DOT = TextAttributesKey.createTextAttributesKey("TXTPB_DOT", DefaultLanguageHighlighterColors.DOT) + val SEMICOLON = + TextAttributesKey.createTextAttributesKey("TXTPB_SEMICOLON", DefaultLanguageHighlighterColors.SEMICOLON) + val COMMA = TextAttributesKey.createTextAttributesKey("TXTPB_COMMA", DefaultLanguageHighlighterColors.COMMA) + val PARENTHESES = + TextAttributesKey.createTextAttributesKey( + "TXTPB_PARENTHESES", + DefaultLanguageHighlighterColors.PARENTHESES, + ) + val BRACKETS = + TextAttributesKey.createTextAttributesKey( + "TXTPB_BRACKETS", + DefaultLanguageHighlighterColors.BRACKETS, + ) + + // Invalid characters. + val BAD_CHARACTER = + TextAttributesKey.createTextAttributesKey( + "TXTPB_BAD_CHARACTER", + HighlighterColors.BAD_CHARACTER, + ) + + val attributesMap = + mapOf( + ProtoTextTokens.IDENTIFIER_LITERAL to IDENTIFIER, + ProtoTextTokens.ASSIGN to OPERATION_SIGN, + ProtoTextTokens.COLON to OPERATION_SIGN, + ProtoTextTokens.COMMA to COMMA, + ProtoTextTokens.DOT to DOT, + ProtoTextTokens.GT to BRACES, + ProtoTextTokens.LBRACE to BRACES, + ProtoTextTokens.LBRACK to BRACKETS, + ProtoTextTokens.LPAREN to PARENTHESES, + ProtoTextTokens.LT to BRACES, + ProtoTextTokens.MINUS to OPERATION_SIGN, + ProtoTextTokens.PLUS to OPERATION_SIGN, + ProtoTextTokens.RBRACE to BRACES, + ProtoTextTokens.RBRACK to BRACKETS, + ProtoTextTokens.RPAREN to PARENTHESES, + ProtoTextTokens.SEMI to SEMICOLON, + ProtoTextTokens.SLASH to OPERATION_SIGN, + ProtoTextTokens.FLOAT_LITERAL to NUMBER, + ProtoTextTokens.INTEGER_LITERAL to NUMBER, + ProtoTextTokens.STRING_LITERAL to STRING, + ProtoTextTokens.SHARP_LINE_COMMENT to LINE_COMMENT, + ProtoTextTokens.BUILT_IN_TYPE to KEYWORD, + ProtoTextTokens.FALSE to KEYWORD, + ProtoTextTokens.TRUE to KEYWORD, + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlightingAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlightingAnnotator.kt new file mode 100644 index 00000000..86377efe --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtoTextHighlightingAnnotator.kt @@ -0,0 +1,57 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.codeInsight.daemon.impl.HighlightInfoType +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.psi.PsiElement +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextNumberValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextVisitor + +class ProtoTextHighlightingAnnotator : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + ProtoTextHighlightingAnnotator.annotate(element, holder) + } + + companion object : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + element.accept( + object : ProtoTextVisitor() { + override fun visitEnumValue(o: ProtoTextEnumValue) { + createHighlight(o, ProtoTextHighlighter.ENUM_VALUE) + } + + override fun visitNumberValue(o: ProtoTextNumberValue) { + if (o.floatLiteral == null && o.integerLiteral == null) { + createHighlight(o, ProtoTextHighlighter.NUMBER) + } + } + + override fun visitFieldName(o: ProtoTextFieldName) { + if (o.symbolName != null) { + createHighlight(o, ProtoTextHighlighter.FIELD) + } + } + + private fun createHighlight( + element: PsiElement, + textAttributesKey: TextAttributesKey, + ) { + holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) + .range(element.textRange) + .textAttributes(textAttributesKey) + .create() + } + }, + ) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufColorSettingsPage.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufColorSettingsPage.kt new file mode 100644 index 00000000..d1a383df --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufColorSettingsPage.kt @@ -0,0 +1,98 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.fileTypes.SyntaxHighlighter +import com.intellij.openapi.options.colors.AttributesDescriptor +import com.intellij.openapi.options.colors.ColorDescriptor +import com.intellij.openapi.options.colors.ColorSettingsPage +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import javax.swing.Icon + +class ProtobufColorSettingsPage : ColorSettingsPage { + override fun getAttributeDescriptors(): Array { + return DESCRIPTORS + } + + override fun getColorDescriptors(): Array { + return ColorDescriptor.EMPTY_ARRAY + } + + override fun getDisplayName(): String { + return "Protobuf" + } + + override fun getIcon(): Icon { + return ProtobufIcons.FILE + } + + override fun getHighlighter(): SyntaxHighlighter { + return ProtobufHighlighter() + } + + override fun getDemoText(): String { + return """ + /* + * Block Comments + */ + syntax = "proto3"; + + package protobuf_unittest; // Line Comment + + import "google/protobuf/any.proto"; + + option java_outer_classname = "TestAnyProto"; + + // Doc Comment + message TestMessage { + int32 int32_value = 1 [default = 10086]; + google.protobuf.Any any_value = 2; + repeated google.protobuf.Any repeated_any_value = 3; + string text = 4 [default = "test_default"]; + } + + enum TestEnum { + UNKNOWN = 0, + VALUE = 1 + } + + service TestService { + rpc TestMethod(TestMessage) returns (google.protobuf.Empty) { + option (google.api.http) = { + post: "/v1/test" + body: "*" + }; + } + } + """.trimIndent() + } + + override fun getAdditionalHighlightingTagToDescriptorMap(): MutableMap? { + return mutableMapOf() + } + + companion object { + val DESCRIPTORS = + arrayOf( + AttributesDescriptor("Braces and Operators//Braces", ProtobufHighlighter.BRACES), + AttributesDescriptor("Braces and Operators//Brackets", ProtobufHighlighter.BRACKETS), + AttributesDescriptor("Braces and Operators//Comma", ProtobufHighlighter.COMMA), + AttributesDescriptor("Braces and Operators//Dot", ProtobufHighlighter.DOT), + AttributesDescriptor("Braces and Operators//Operator sign", ProtobufHighlighter.OPERATION_SIGN), + AttributesDescriptor("Braces and Operators//Parentheses", ProtobufHighlighter.PARENTHESES), + AttributesDescriptor("Braces and Operators//Semicolon", ProtobufHighlighter.SEMICOLON), + AttributesDescriptor("Comments//Block comment", ProtobufHighlighter.BLOCK_COMMENT), + AttributesDescriptor("Comments//Line comment", ProtobufHighlighter.LINE_COMMENT), + AttributesDescriptor("Comments//Doc comment", ProtobufHighlighter.DOC_COMMENT), + AttributesDescriptor("Identifiers//Default", ProtobufHighlighter.IDENTIFIER), + AttributesDescriptor("Identifiers//Message", ProtobufHighlighter.MESSAGE), + AttributesDescriptor("Identifiers//Field", ProtobufHighlighter.FIELD), + AttributesDescriptor("Identifiers//Enum", ProtobufHighlighter.ENUM), + AttributesDescriptor("Identifiers//Enum value", ProtobufHighlighter.ENUM_VALUE), + AttributesDescriptor("Identifiers//Service", ProtobufHighlighter.SERVICE), + AttributesDescriptor("Identifiers//Method", ProtobufHighlighter.METHOD), + AttributesDescriptor("Keyword", ProtobufHighlighter.KEYWORD), + AttributesDescriptor("Number", ProtobufHighlighter.NUMBER), + AttributesDescriptor("String", ProtobufHighlighter.STRING), + ) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightLexer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightLexer.kt similarity index 81% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightLexer.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightLexer.kt index d041cb1e..bf0583f4 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlightLexer.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightLexer.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.highligh +package io.kanro.idea.plugin.protobuf.lang.highlight import com.intellij.lexer.DelegateLexer import com.intellij.lexer.Lexer import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType class ProtobufHighlightLexer(delegate: Lexer) : DelegateLexer(delegate) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlighter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlighter.kt similarity index 96% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlighter.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlighter.kt index 7cd9ad43..911ecdf3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highligh/ProtobufHighlighter.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlighter.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.highligh +package io.kanro.idea.plugin.protobuf.lang.highlight import com.intellij.lexer.Lexer import com.intellij.openapi.editor.DefaultLanguageHighlighterColors @@ -7,7 +7,7 @@ import com.intellij.openapi.editor.colors.TextAttributesKey import com.intellij.openapi.fileTypes.SyntaxHighlighterBase import com.intellij.psi.tree.IElementType import io.kanro.idea.plugin.protobuf.lang.lexer.ProtobufLexer -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufHighlighter : SyntaxHighlighterBase() { override fun getHighlightingLexer(): Lexer { @@ -129,6 +129,7 @@ class ProtobufHighlighter : SyntaxHighlighterBase() { ProtobufTokens.LPAREN to PARENTHESES, ProtobufTokens.LT to BRACES, ProtobufTokens.MINUS to OPERATION_SIGN, + ProtobufTokens.PLUS to OPERATION_SIGN, ProtobufTokens.RBRACE to BRACES, ProtobufTokens.RBRACK to BRACKETS, ProtobufTokens.RPAREN to PARENTHESES, @@ -164,6 +165,7 @@ class ProtobufHighlighter : SyntaxHighlighterBase() { ProtobufTokens.SERVICE to KEYWORD, ProtobufTokens.STREAM to KEYWORD, ProtobufTokens.SYNTAX to KEYWORD, + ProtobufTokens.EDITION to KEYWORD, ProtobufTokens.TO to KEYWORD, ProtobufTokens.TRUE to KEYWORD, ProtobufTokens.WEAK to KEYWORD, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightingAnnotator.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightingAnnotator.kt new file mode 100644 index 00000000..c4c50083 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/highlight/ProtobufHighlightingAnnotator.kt @@ -0,0 +1,99 @@ +package io.kanro.idea.plugin.protobuf.lang.highlight + +import com.intellij.codeInsight.daemon.impl.HighlightInfoType +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.psi.PsiComment +import com.intellij.psi.PsiElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufNumberValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufVisitor + +class ProtobufHighlightingAnnotator : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + ProtobufHighlightingAnnotator.annotate(element, holder) + } + + companion object : Annotator { + override fun annotate( + element: PsiElement, + holder: AnnotationHolder, + ) { + element.accept( + object : ProtobufVisitor() { + override fun visitEnumValueDefinition(o: ProtobufEnumValueDefinition) { + createHighlight(o.identifier() ?: return, ProtobufHighlighter.ENUM_VALUE) + } + + override fun visitPackageName(o: ProtobufPackageName) { + createHighlight(o, ProtobufHighlighter.IDENTIFIER) + } + + override fun visitIdentifier(o: ProtobufIdentifier) { + when (o.parent) { + is ProtobufMessageDefinition -> createHighlight(o, ProtobufHighlighter.MESSAGE) + is ProtobufFieldDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) + is ProtobufMapFieldDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) + is ProtobufOneofDefinition -> createHighlight(o, ProtobufHighlighter.FIELD) + is ProtobufGroupDefinition -> createHighlight(o, ProtobufHighlighter.MESSAGE) + is ProtobufEnumDefinition -> createHighlight(o, ProtobufHighlighter.ENUM) + is ProtobufServiceDefinition -> createHighlight(o, ProtobufHighlighter.SERVICE) + is ProtobufRpcDefinition -> createHighlight(o, ProtobufHighlighter.METHOD) + } + } + + override fun visitComment(comment: PsiComment) { + if (comment is DocumentElement) { + if (comment.owner != null) { + createHighlight(comment, ProtobufHighlighter.DOC_COMMENT) + } + } + } + + override fun visitEnumValue(o: ProtobufEnumValue) { + createHighlight(o, ProtobufHighlighter.ENUM_VALUE) + } + + override fun visitNumberValue(o: ProtobufNumberValue) { + if (o.floatLiteral == null && o.integerLiteral == null) { + createHighlight(o, ProtobufHighlighter.KEYWORD) + } + } + + override fun visitExtensionFieldName(o: ProtobufExtensionFieldName) { + if (o.extensionFieldName == null) { + createHighlight(o.symbolName, ProtobufHighlighter.FIELD) + } + } + + private fun createHighlight( + element: PsiElement, + textAttributesKey: TextAttributesKey, + ) { + holder.newSilentAnnotation(HighlightInfoType.SYMBOL_TYPE_SEVERITY) + .range(element.textRange) + .textAttributes(textAttributesKey) + .create() + } + }, + ) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtoTextLexer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtoTextLexer.kt new file mode 100644 index 00000000..ce1cc762 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtoTextLexer.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.lexer + +import com.intellij.lexer.FlexAdapter +import io.kanro.idea.plugin.protobuf.lang.lexer.text._ProtoTextLexer + +class ProtoTextLexer : FlexAdapter(_ProtoTextLexer(null)) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtobufLexer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtobufLexer.kt index 38880d1a..08de3131 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtobufLexer.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/lexer/ProtobufLexer.kt @@ -1,5 +1,6 @@ package io.kanro.idea.plugin.protobuf.lang.lexer import com.intellij.lexer.FlexAdapter +import io.kanro.idea.plugin.protobuf.lang.lexer.proto._ProtobufLexer class ProtobufLexer : FlexAdapter(_ProtobufLexer(null)) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/BaseElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/BaseElement.kt new file mode 100644 index 00000000..bac01d9f --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/BaseElement.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi + +import com.intellij.psi.PsiElement + +interface BaseElement : PsiElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/Extension.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/Extension.kt index e46286f3..70b5162c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/Extension.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/Extension.kt @@ -1,27 +1,14 @@ package io.kanro.idea.plugin.protobuf.lang.psi -import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiElementFilter import com.intellij.psi.util.PsiModificationTracker -import com.intellij.psi.util.QualifiedName -import com.intellij.psi.util.elementType -import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItemContainer -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufVirtualScope -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufKeywordToken -import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes -import io.kanro.idea.plugin.protobuf.string.parseDoubleOrNull -import io.kanro.idea.plugin.protobuf.string.parseLongOrNull -import io.kanro.idea.plugin.protobuf.string.toCamelCase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItemContainer +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufVirtualScope import java.util.Stack fun PsiElement.firstLeaf(): PsiElement { @@ -156,125 +143,6 @@ inline fun PsiElement.forEachPrev(block: (PsiElement) -> Unit) { } } -fun ProtobufImportStatement.public(): Boolean { - return importLabel?.textMatches("public") == true -} - -fun ProtobufImportStatement.weak(): Boolean { - return importLabel?.textMatches("weak") == true -} - -fun ProtobufImportStatement.resolve(): ProtobufFile? { - return reference?.resolve() as? ProtobufFile -} - -fun ProtobufOptionName.field(): ProtobufFieldLike? { - this.fieldNameList.lastOrNull()?.let { - return it.reference?.resolve() as? ProtobufFieldLike - } - this.extensionOptionName?.let { - return it.typeName?.reference?.resolve() as? ProtobufFieldLike - } - this.builtInOptionName?.let { - return it.reference?.resolve() as? ProtobufFieldLike - } - return null -} - -fun ProtobufFieldName.message(): ProtobufScope? { - val parent = - when (val parent = this.parent) { - is ProtobufArrayValue -> { - parent.parent.parent - } - - else -> parent - } - - val field = - when (parent) { - is ProtobufOptionName -> { - val prevField = this.prev() - if (prevField == null) { - parent.extensionOptionName?.typeName?.reference?.resolve() - } else { - prevField.reference?.resolve() - } - } - - is ProtobufFieldAssign -> { - val messageValue = parent.parent as? ProtobufMessageValue ?: return null - val assign = - when (val assign = messageValue.parent.parent) { - is ProtobufArrayValue -> { - assign.parent.parent - } - - else -> assign - } - - when (assign) { - is ProtobufOptionAssign -> { - assign.optionName.field() - } - - is ProtobufFieldAssign -> { - assign.fieldName.reference?.resolve() as? ProtobufDefinition - } - - else -> null - } - } - - else -> null - } ?: return null - - return when (field) { - is ProtobufGroupDefinition -> field - is ProtobufFieldDefinition -> field.typeName.reference?.resolve() as? ProtobufMessageDefinition - else -> null - } -} - -fun ProtobufBuiltInOptionName.isFieldDefaultOption(): Boolean { - return this.textMatches("default") && parentOfType() is ProtobufFieldDefinition -} - -fun ProtobufBuiltInOptionName.isFieldJsonNameOption(): Boolean { - return this.textMatches("json_name") && parentOfType() is ProtobufFieldDefinition -} - -fun ProtobufEnumValue.enum(): ProtobufEnumDefinition? { - val field = - when (val parent = this.parent.parent) { - is ProtobufOptionAssign -> { - parent.optionName.field() as? ProtobufFieldDefinition - } - - is ProtobufFieldAssign -> { - parent.fieldName.reference?.resolve() as? ProtobufFieldDefinition - } - - else -> null - } ?: return null - return field.typeName.reference?.resolve() as? ProtobufEnumDefinition -} - -fun ProtobufReservedRange.range(): LongRange? { - val numbers = integerValueList.map { it.text.toLong() } - return when (numbers.size) { - 1 -> - if (lastChild.textMatches("max")) { - LongRange(numbers[0], Long.MAX_VALUE) - } else { - LongRange(numbers[0], numbers[0]) - } - - 2 -> LongRange(numbers[0], numbers[1]) - else -> null - } -} - operator fun ProtobufScope.iterator(): Iterator { return realItems().iterator() } @@ -342,215 +210,5 @@ fun ProtobufScope.realItems(): Array { return result.toTypedArray() } -fun ProtobufStringValue.value(): String? { - return stringLiteral.text?.trim('"') -} - -fun ProtobufStringValue.stringRange(): TextRange { - return stringRange(textRange) -} - -fun ProtobufStringValue.stringRangeInParent(): TextRange { - return stringRange(textRangeInParent) -} - -private fun ProtobufStringValue.stringRange(relativelyRange: TextRange): TextRange { - var textRange = relativelyRange - val text = text - - if (textRange.length == 0) return textRange - if (text.startsWith('"')) { - textRange = TextRange.create(textRange.startOffset + 1, textRange.endOffset) - } - if (textRange.length == 0) return textRange - if (text.endsWith('"')) { - textRange = TextRange.create(textRange.startOffset, textRange.endOffset - 1) - } - return textRange -} - -fun ProtobufNumberValue.float(): Double? { - return floatLiteral?.text?.parseDoubleOrNull() - ?: integerLiteral?.text?.parseLongOrNull()?.toDouble() -} - -fun ProtobufNumberValue.int(): Long? { - return integerLiteral?.text?.parseLongOrNull() -} - -fun ProtobufNumberValue.uint(): Long? { - return int() -} - -fun ProtobufBooleanValue.value(): Boolean { - return textMatches("true") -} - -fun ProtobufConstant.stringValue(): String? { - if (stringValueList.isEmpty()) return null - return stringValueList.joinToString("") { it.value() ?: "" } -} - -fun ProtobufRpcIO.stream(): Boolean { - this.walkChildren(false) { - if (it.elementType is ProtobufKeywordToken && it.textMatches("stream")) { - return true - } - } - return false -} - -fun ProtobufFieldLike.jsonName(): String? { - return CachedValuesManager.getCachedValue(this) { - val option = (this as? ProtobufOptionOwner)?.options("json_name")?.lastOrNull() - val result = - option?.value()?.stringValue() - ?: name()?.toCamelCase() - CachedValueProvider.Result.create( - result, - PsiModificationTracker.MODIFICATION_COUNT, - ) - } -} - -/** - * Resolve type of qualified field for a message definition. - * It could be returning a [ProtobufMessageDefinition] for message field. - * returning a [ProtobufEnumDefinition] for enum field. - * returning a [ProtobufMapFieldDefinition] for map field. - * returning a [ProtobufGroupDefinition] for group field. - */ -fun ProtobufMessageDefinition.resolveFieldType( - qualifiedName: QualifiedName, - jsonSpec: Boolean = false, -): ProtobufElement? { - if (qualifiedName.components.isEmpty()) return this - - val q = - Stack().apply { - addAll(qualifiedName.components.asReversed()) - } - - var scope: ProtobufScope = this - - while (q.isNotEmpty()) { - val field = q.pop() - - if (jsonSpec) { - if (scope is ProtobufMessageDefinition) { - val message = scope.qualifiedName().toString() - if (message == WellknownTypes.ANY && field == "@type") { - return scope.firstItemOrNull { - it.name() == "type_url" - } - } else if (message in WellknownTypes.types) { - return null - } - } - } - - val fieldDefinition = - scope.firstItemOrNull { - it.name() == field || it.jsonName() == field - } ?: return null - - when (fieldDefinition) { - is ProtobufFieldDefinition -> { - val type = fieldDefinition.typeName.reference?.resolve() as? ProtobufElement ?: return null - if (q.isEmpty()) return type - scope = type as? ProtobufMessageDefinition ?: return null - } - - is ProtobufMapFieldDefinition -> { - if (q.isEmpty()) return fieldDefinition - q.pop() - val type = - fieldDefinition.typeNameList.lastOrNull()?.reference?.resolve() as? ProtobufElement - ?: return null - if (q.isEmpty()) return type - scope = type as? ProtobufMessageDefinition ?: return null - } - - is ProtobufGroupDefinition -> { - scope = fieldDefinition - if (q.isEmpty()) return scope - } - } - } - return null -} - -/** - * Resolve qualified field for a message definition. - * It could be returning any [ProtobufFieldLike]. - */ -fun ProtobufMessageDefinition.resolveField( - qualifiedName: QualifiedName, - jsonSpec: Boolean = false, -): ProtobufFieldLike? { - val field = qualifiedName.lastComponent ?: return null - val parentField = qualifiedName.removeTail(1) - val parentType = resolveFieldType(parentField, jsonSpec) ?: return null - - if (jsonSpec) { - if (parentType is ProtobufMessageDefinition) { - val message = parentType.qualifiedName().toString() - if (message == WellknownTypes.ANY && field == "@type") { - return parentType.firstItemOrNull { - it.name() == "type_url" - } - } else if (message in WellknownTypes.types) { - return null - } - } - } - - return when (parentType) { - is ProtobufMessageDefinition -> { - parentType.firstItemOrNull { it.name() == field || it.jsonName() == field } - } - - is ProtobufGroupDefinition -> { - parentType.firstItemOrNull { it.name() == field || it.jsonName() == field } - } - - else -> null - } -} - -fun ProtobufFieldDefinition.repeated(): Boolean { - return this.fieldLabel?.textMatches("repeated") == true -} - -fun ProtobufGroupDefinition.repeated(): Boolean { - return this.fieldLabel?.textMatches("repeated") == true -} - -fun ProtobufFieldDefinition.required(): Boolean { - return this.fieldLabel?.textMatches("required") == true -} - -fun ProtobufGroupDefinition.required(): Boolean { - return this.fieldLabel?.textMatches("required") == true -} - -fun ProtobufFieldDefinition.optional(): Boolean { - return this.fieldLabel?.textMatches("optional") == true -} - -fun ProtobufGroupDefinition.optional(): Boolean { - return this.fieldLabel?.textMatches("optional") == true -} - -fun ProtobufMapFieldDefinition.key(): ProtobufTypeName? { - if (typeNameList.size < 2) return null - return typeNameList[0] -} - -fun ProtobufMapFieldDefinition.value(): ProtobufTypeName? { - if (typeNameList.size < 2) return null - return typeNameList[1] -} - fun nullCachedValue(): CachedValueProvider.Result = CachedValueProvider.Result.create(null, PsiModificationTracker.MODIFICATION_COUNT) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufElementType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufElementType.kt deleted file mode 100644 index 47936fab..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufElementType.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi - -import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage - -open class ProtobufElementType(name: String) : IElementType(name, ProtobufLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBody.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyElement.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBody.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyElement.kt index 9def505b..ca708921 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBody.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyElement.kt @@ -1,11 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify +package io.kanro.idea.plugin.protobuf.lang.psi.feature import com.intellij.lang.folding.FoldingDescriptor import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFolding -interface ProtobufBody : ProtobufFolding { - fun owner(): ProtobufBodyOwner { +interface BodyElement : FoldingElement { + fun owner(): BodyOwner { return parentOfType() ?: throw IllegalStateException() } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyOwner.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyOwner.kt new file mode 100644 index 00000000..09163cac --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/BodyOwner.kt @@ -0,0 +1,10 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild + +interface BodyOwner : BaseElement { + fun body(): BodyElement? { + return findChild() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocument.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentElement.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocument.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentElement.kt index f823cdc5..9ab01e66 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocument.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentElement.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.feature import com.intellij.psi.PsiDocCommentBase import com.intellij.psi.PsiElement import com.intellij.psi.PsiWhiteSpace -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition -interface ProtobufDocument : PsiDocCommentBase { +interface DocumentElement : PsiDocCommentBase { override fun getOwner(): PsiElement? { var next = nextSibling var newLine = 0 diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocumented.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentOwner.kt similarity index 59% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocumented.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentOwner.kt index 38d97787..9e4f67f6 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufDocumented.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/DocumentOwner.kt @@ -1,15 +1,15 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.feature -import com.intellij.psi.PsiElement +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement import io.kanro.idea.plugin.protobuf.lang.psi.prev -interface ProtobufDocumented : PsiElement { +interface DocumentOwner : BaseElement { fun navigateInfo(): String? { return null } fun document(): String? { - val document = this.prev() + val document = this.prev() if (document?.owner != this) return null return document.render() } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/FoldingElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/FoldingElement.kt new file mode 100644 index 00000000..e7251028 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/FoldingElement.kt @@ -0,0 +1,8 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import com.intellij.lang.folding.FoldingDescriptor +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement + +interface FoldingElement : BaseElement { + fun folding(): FoldingDescriptor? +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/LookupableElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/LookupableElement.kt new file mode 100644 index 00000000..3b5b342d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/LookupableElement.kt @@ -0,0 +1,9 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.navigation.NavigationItem +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement + +interface LookupableElement : BaseElement, NavigationItem { + fun lookup(name: String? = null): LookupElementBuilder? +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/NamedElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/NamedElement.kt new file mode 100644 index 00000000..9e7a2b2e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/NamedElement.kt @@ -0,0 +1,7 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement + +interface NamedElement : BaseElement { + fun name(): String? +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumbered.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ProtobufNumbered.kt similarity index 61% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumbered.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ProtobufNumbered.kt index 7604d2af..a46f9453 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumbered.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ProtobufNumbered.kt @@ -1,7 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.feature -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIntegerValue import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIntegerValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition import io.kanro.idea.plugin.protobuf.string.parseLongOrNull interface ProtobufNumbered : ProtobufDefinition { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/QualifiedElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/QualifiedElement.kt new file mode 100644 index 00000000..381c8878 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/QualifiedElement.kt @@ -0,0 +1,13 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import com.intellij.psi.PsiElement + +interface QualifiedElement> : ReferenceElement { + fun root(): T + + fun leaf(): T + + override fun resolve(): PsiElement? { + return leaf().reference?.resolve() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ReferenceElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ReferenceElement.kt new file mode 100644 index 00000000..57f666ac --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ReferenceElement.kt @@ -0,0 +1,14 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import com.intellij.psi.PsiElement +import com.intellij.psi.util.QualifiedName + +interface ReferenceElement : PsiElement { + fun symbol(): QualifiedName? + + fun rename(qualifiedName: QualifiedName) + + fun resolve(): PsiElement? { + return reference?.resolve() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueAssign.kt new file mode 100644 index 00000000..ebf0dfad --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueAssign.kt @@ -0,0 +1,9 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.value.WrappedValue + +interface ValueAssign : BaseElement, WrappedValue { + fun field(): ProtobufFieldLike? +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueElement.kt new file mode 100644 index 00000000..54e5286b --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/feature/ValueElement.kt @@ -0,0 +1,19 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement + +interface ValueElement : BaseElement { + fun value(): T + + fun valueType(): ValueType +} + +enum class ValueType { + UNKNOWN, + STRING, + NUMBER, + BOOLEAN, + ENUM, + MESSAGE, + LIST, +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufBuiltInOptionMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufBuiltInOptionMixin.kt deleted file mode 100644 index 0179074b..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufBuiltInOptionMixin.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufBuiltInOptionReference - -abstract class ProtobufBuiltInOptionMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufBuiltInOptionName { - override fun getReference(): PsiReference { - return ProtobufBuiltInOptionReference(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufEnumValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufEnumValueMixin.kt deleted file mode 100644 index e8c6de90..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufEnumValueMixin.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufEnumValueReference - -abstract class ProtobufEnumValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufEnumValue { - override fun getReference(): PsiReference { - return ProtobufEnumValueReference(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufFieldNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufFieldNameMixin.kt deleted file mode 100644 index 60bd22fa..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufFieldNameMixin.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiReference -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufFieldReference - -abstract class ProtobufFieldNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufFieldName { - override fun getReference(): PsiReference { - return ProtobufFieldReference(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufStringValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufStringValueMixin.kt deleted file mode 100644 index 433a0802..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufStringValueMixin.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.psi.PsiReference -import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase - -abstract class ProtobufStringValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufStringValue { - override fun getReference(): PsiReference? { - return references.firstOrNull() - } - - override fun getReferences(): Array { - return ReferenceProvidersRegistry.getReferencesFromProviders(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufTypeNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufTypeNameMixin.kt deleted file mode 100644 index a720fc56..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufTypeNameMixin.kt +++ /dev/null @@ -1,74 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin - -import com.intellij.lang.ASTNode -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiReference -import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry -import com.intellij.psi.impl.source.tree.LeafElement -import com.intellij.psi.util.PsiElementFilter -import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcIO -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSymbolName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters -import io.kanro.idea.plugin.protobuf.lang.util.ProtobufPsiFactory - -abstract class ProtobufTypeNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufTypeName { - private val hover = - object : ProtobufSymbolReferenceHover { - override fun symbolParts(): List { - return symbolNameList.map { - ProtobufSymbolReferenceHover.SymbolPart(it.startOffsetInParent, it.text) - } - } - - override fun textRange(): TextRange { - return textRange - } - - override fun renamePart( - index: Int, - newName: String, - ) { - (symbolNameList[index].identifierLiteral?.node as? LeafElement)?.replaceWithText(newName) - } - - override fun rename(newName: String) { - replace(ProtobufPsiFactory.createTypeName(project, newName)) - } - - override fun absolutely(): Boolean { - return firstChild !is ProtobufSymbolName - } - - override fun variantFilter(): PsiElementFilter { - return when (parent) { - is ProtobufExtensionOptionName -> ProtobufSymbolFilters.extensionOptionNameVariants(parentOfType()) - is ProtobufFieldDefinition, - is ProtobufMapFieldDefinition, - -> ProtobufSymbolFilters.fieldTypeNameVariants - is ProtobufRpcIO -> ProtobufSymbolFilters.rpcTypeNameVariants - is ProtobufExtendDefinition -> ProtobufSymbolFilters.extendTypeNameVariants - else -> ProtobufSymbolFilters.alwaysFalse - } - } - } - - override fun referencesHover(): ProtobufSymbolReferenceHover { - return hover - } - - override fun getReference(): PsiReference? { - return references.firstOrNull() - } - - override fun getReferences(): Array { - return ReferenceProvidersRegistry.getReferencesFromProviders(this) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldAssign.kt deleted file mode 100644 index 8b9f1802..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldAssign.kt +++ /dev/null @@ -1,24 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element - -import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufValueAssign - -interface ProtobufFieldAssign : ProtobufValueAssign { - override fun field(): ProtobufFieldLike? { - val targetField = findChild()?.text ?: return null - val parentAssign = parentOfType() ?: return null - val message = - (parentAssign.field() as? ProtobufFieldDefinition)?.typeName?.reference?.resolve() as? ProtobufMessageDefinition - ?: return null - - message.items { - if (it.name() == targetField) return it - } - return null - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldDefinition.kt deleted file mode 100644 index 6711af7e..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufFieldDefinition.kt +++ /dev/null @@ -1,51 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element - -import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValuesManager -import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufMultiNameDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue -import javax.swing.Icon - -interface ProtobufFieldDefinition : ProtobufFieldLike, ProtobufMultiNameDefinition { - override fun type(): String { - return "field" - } - - override fun getIcon(unused: Boolean): Icon? { - return ProtobufIcons.FIELD - } - - fun resourceType(): String? { - if (this !is ProtobufOptionOwner) return null - return CachedValuesManager.getCachedValue(this) { - options(AipOptions.resourceReferenceOption).forEach { - it.value(AipOptions.resourceTypeField)?.stringValue()?.let { - return@getCachedValue CachedValueProvider.Result.create( - it, - PsiModificationTracker.MODIFICATION_COUNT, - ) - } - } - return@getCachedValue CachedValueProvider.Result.create(null, PsiModificationTracker.MODIFICATION_COUNT) - } - } - - override fun fieldType(): String? { - resourceType()?.let { - return it - } - return findChild()?.symbolNameList?.lastOrNull()?.text - } - - override fun names(): Set { - return setOfNotNull(name(), jsonName()) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMapFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMapFieldDefinition.kt deleted file mode 100644 index 860f2a93..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMapFieldDefinition.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element - -import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName -import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufMultiNameDefinition -import javax.swing.Icon - -interface ProtobufMapFieldDefinition : ProtobufFieldLike, ProtobufMultiNameDefinition { - override fun type(): String { - return "field" - } - - override fun getIcon(unused: Boolean): Icon? { - return ProtobufIcons.FIELD - } - - override fun fieldType(): String? { - val typeNames = findChildren() - if (typeNames.size != 2) return "map" - val key = typeNames[0].symbolNameList.lastOrNull()?.text ?: return "map" - val value = typeNames[1].symbolNameList.lastOrNull()?.text ?: return "map" - - return "map<$key, $value>" - } - - override fun names(): Set { - return setOfNotNull(name(), jsonName()) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOptionAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOptionAssign.kt deleted file mode 100644 index 6916f595..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOptionAssign.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element - -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.field -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufValueAssign - -interface ProtobufOptionAssign : ProtobufValueAssign { - override fun field(): ProtobufFieldLike? { - return findChild()?.field() - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFileReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFileReferenceContributor.kt deleted file mode 100644 index 86a4a1ab..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFileReferenceContributor.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufFileReferenceContributor : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFolding.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFolding.kt deleted file mode 100644 index 4c4e6357..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufFolding.kt +++ /dev/null @@ -1,8 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import com.intellij.lang.folding.FoldingDescriptor -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufFolding : ProtobufElement { - fun folding(): FoldingDescriptor? -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufLookupItem.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufLookupItem.kt deleted file mode 100644 index 41ec4b97..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufLookupItem.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.navigation.NavigationItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufLookupItem : ProtobufElement, NavigationItem { - fun lookup(name: String? = null): LookupElementBuilder? -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufNamedElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufNamedElement.kt deleted file mode 100644 index f8de01cf..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufNamedElement.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufNamedElement : ProtobufElement { - fun name(): String? -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufSymbolReferenceHost.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufSymbolReferenceHost.kt deleted file mode 100644 index 71bbf74f..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufSymbolReferenceHost.kt +++ /dev/null @@ -1,54 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature - -import com.intellij.openapi.extensions.ExtensionPointName -import com.intellij.openapi.util.TextRange -import com.intellij.psi.util.PsiElementFilter -import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufSymbolReferenceHost : ProtobufElement { - fun referencesHover(): ProtobufSymbolReferenceHover? { - return ProtobufSymbolReferenceProvider.hovers(this) - } -} - -interface ProtobufSymbolReferenceProvider { - fun hovers(element: ProtobufSymbolReferenceHost): ProtobufSymbolReferenceHover? - - companion object : ProtobufSymbolReferenceProvider { - var extensionPoint: ExtensionPointName = - ExtensionPointName.create("io.kanro.idea.plugin.protobuf.symbolReferenceProvider") - - override fun hovers(element: ProtobufSymbolReferenceHost): ProtobufSymbolReferenceHover? { - extensionPoint.extensionList.forEach { - it.hovers(element)?.let { - return it - } - } - return null - } - } -} - -interface ProtobufSymbolReferenceHover { - fun symbol(): QualifiedName { - return QualifiedName.fromComponents(symbolParts().map { it.value }) - } - - fun textRange(): TextRange - - fun symbolParts(): List - - fun renamePart( - index: Int, - newName: String, - ) - - fun rename(newName: String) - - fun absolutely(): Boolean - - fun variantFilter(): PsiElementFilter - - data class SymbolPart(val startOffset: Int, val value: String) -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBodyOwner.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBodyOwner.kt deleted file mode 100644 index a557bc28..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufBodyOwner.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify - -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufBodyOwner : ProtobufElement { - fun body(): ProtobufBody? { - return findChild() - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionHover.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionHover.kt deleted file mode 100644 index d1ccdfab..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionHover.kt +++ /dev/null @@ -1,50 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify - -import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufConstant -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionAssign -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufOptionHover : ProtobufElement { - fun option(): ProtobufOptionAssign? { - return findChild() - } - - fun isOption(extensionOptionName: QualifiedName): Boolean { - val option = option() ?: return false - val field = - option.optionName.extensionOptionName?.typeName?.reference?.resolve() as? ProtobufFieldDefinition - ?: return false - return field.qualifiedName() == extensionOptionName - } - - fun isOption(builtinOptionName: String): Boolean { - val option = option() ?: return false - return option.optionName.builtInOptionName?.textMatches(builtinOptionName) == true - } - - fun value(): ProtobufConstant? { - return option()?.findChild() - } - - fun value(field: QualifiedName): ProtobufConstant? { - if (field.componentCount == 0) return value() - val optionName = option()?.optionName ?: return null - var findName = field - optionName.fieldNameList.forEach { - if (!it.textMatches(findName.firstComponent ?: return null)) return null - findName = findName.removeHead(1) - } - var value = value() ?: return null - while (findName.componentCount != 0) { - val messageValue = value.messageValue ?: return null - value = messageValue.fieldAssignList.firstOrNull { - it.fieldName.textMatches(findName.firstComponent ?: return null) - }?.constant ?: return null - findName = findName.removeHead(1) - } - return value - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufFieldLike.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufFieldLike.kt deleted file mode 100644 index 563718c5..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufFieldLike.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure - -interface ProtobufFieldLike : ProtobufDefinition, ProtobufNumbered { - fun fieldName(): String? { - return name() - } - - fun fieldType(): String? - - override fun tailText(): String? { - return ": ${fieldType()} = ${number()}" - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufValueAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufValueAssign.kt deleted file mode 100644 index 72427a65..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufValueAssign.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure - -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufConstant -import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufValueAssign : ProtobufElement { - fun value(): ProtobufConstant? { - return findChild() - } - - fun field(): ProtobufFieldLike? -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufVirtualScope.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufVirtualScope.kt deleted file mode 100644 index bb1800ff..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufVirtualScope.kt +++ /dev/null @@ -1,3 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure - -interface ProtobufVirtualScope : ProtobufScopeItemContainer diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufBlock.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufBlock.kt deleted file mode 100644 index 3d0baa78..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufBlock.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.type - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufBlock : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufFragment.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufFragment.kt deleted file mode 100644 index 064f3f22..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufFragment.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.type - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufFragment : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufStatement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufStatement.kt deleted file mode 100644 index a5ecb4e4..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/type/ProtobufStatement.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.type - -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement - -interface ProtobufStatement : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufASTFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufASTFactory.kt similarity index 72% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufASTFactory.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufASTFactory.kt index 15695799..2aeaeb9c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufASTFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufASTFactory.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi +package io.kanro.idea.plugin.protobuf.lang.psi.proto import com.intellij.lang.DefaultASTFactoryImpl import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.impl.source.tree.PsiCommentImpl import com.intellij.psi.tree.IElementType -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufLineCommentImpl -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufASTFactory : DefaultASTFactoryImpl() { override fun createComment( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElement.kt similarity index 64% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElement.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElement.kt index 7047b9da..b7594dd2 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElement.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElement.kt @@ -1,10 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive +package io.kanro.idea.plugin.protobuf.lang.psi.proto -import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver -interface ProtobufElement : PsiElement { +interface ProtobufElement : BaseElement { fun file(): ProtobufFile { return containingFile.originalFile as ProtobufFile } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElementBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementBase.kt similarity index 83% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElementBase.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementBase.kt index 2b6a4c67..d6777ac8 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/ProtobufElementBase.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementBase.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive +package io.kanro.idea.plugin.protobuf.lang.psi.proto import com.intellij.extapi.psi.ASTWrapperPsiElement import com.intellij.lang.ASTNode import com.intellij.navigation.ItemPresentation import com.intellij.psi.PsiElement import com.intellij.psi.PsiNameIdentifierOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement abstract class ProtobufElementBase(node: ASTNode) : ASTWrapperPsiElement(node) { override fun getPresentation(): ItemPresentation? { @@ -24,7 +24,7 @@ abstract class ProtobufElementBase(node: ASTNode) : ASTWrapperPsiElement(node) { } override fun getName(): String? { - if (this is ProtobufNamedElement) return name() + if (this is NamedElement) return name() return null } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementType.kt new file mode 100644 index 00000000..3535eb07 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufElementType.kt @@ -0,0 +1,14 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.lang.ASTNode +import com.intellij.psi.tree.IElementType +import com.intellij.psi.tree.ILazyParseableElementType +import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage + +open class ProtobufElementType(name: String) : IElementType(name, ProtobufLanguage) + +open class ProtoTextInjectionElementType(name: String) : ILazyParseableElementType(name, ProtobufLanguage) { + override fun parseContents(chameleon: ASTNode): ASTNode { + return super.parseContents(chameleon) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufEnumValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufEnumValue.kt new file mode 100644 index 00000000..6d6fea80 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufEnumValue.kt @@ -0,0 +1,26 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign + +fun ProtobufEnumValue.enum(): ProtobufEnumDefinition? { + val assign = parentOfType() ?: return null + val field = assign.field() ?: return null + + return when (field) { + is ProtobufFieldDefinition -> { + field.typeName.resolve() as? ProtobufEnumDefinition + } + + is ProtobufMapFieldDefinition -> { + val targetField = assign.field()?.text ?: return null + when (targetField) { + "key" -> field.key()?.resolve() as? ProtobufEnumDefinition + "value" -> field.value()?.resolve() as? ProtobufEnumDefinition + else -> null + } + } + + else -> null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionFieldName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionFieldName.kt new file mode 100644 index 00000000..0d089949 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionFieldName.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufExtensionFieldName.absolutely(): Boolean { + return this.firstChild !is ProtobufSymbolName +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionRange.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionRange.kt new file mode 100644 index 00000000..ce99e340 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufExtensionRange.kt @@ -0,0 +1,16 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufExtensionRange.range(): LongRange? { + val numbers = integerValueList.map { it.text.toLong() } + return when (numbers.size) { + 1 -> + if (lastChild.textMatches("max")) { + LongRange(numbers[0], Long.MAX_VALUE) + } else { + LongRange(numbers[0], numbers[0]) + } + + 2 -> LongRange(numbers[0], numbers[1]) + else -> null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFieldName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFieldName.kt new file mode 100644 index 00000000..ac8831d5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFieldName.kt @@ -0,0 +1,43 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue + +fun ProtobufFieldName.resolve(): ProtobufElement? { + symbolName?.let { + return reference?.resolve() as? ProtobufElement + } + + extensionName?.let { + return it.extensionFieldName.leaf().reference?.resolve() as? ProtobufElement + } + + anyName?.let { + return it.typeName.leaf().reference?.resolve() as? ProtobufElement + } + + return null +} + +fun ProtobufFieldName.ownerMessage(): ProtobufScope? { + val field = parent as? ProtobufField ?: return null + val message = field.parent as? MessageValue ?: return null + + val parentField = + when (val parentAssign = message.parentOfType()) { + is ProtobufOptionAssign -> parentAssign.field() + + is ProtobufField -> { + parentAssign.fieldName.resolve() + } + + else -> return null + } ?: return null + + if (parentField is ProtobufScope) return parentField + if (parentField is ProtobufFieldDefinition) return parentField.typeName.resolve() as? ProtobufScope + + return null +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufFile.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFile.kt similarity index 64% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufFile.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFile.kt index 52cb3eac..0fc478dc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/ProtobufFile.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufFile.kt @@ -1,23 +1,22 @@ -package io.kanro.idea.plugin.protobuf.lang.psi +package io.kanro.idea.plugin.protobuf.lang.psi.proto import com.intellij.navigation.ItemPresentation import com.intellij.psi.PsiFile import com.intellij.psi.tree.IFileElementType import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubExternalProvider -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubExternalProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope interface ProtobufFile : PsiFile, - ProtobufNamedElement, + NamedElement, ProtobufScope, - ProtobufLookupItem, + LookupableElement, ProtobufOptionOwner, ItemPresentation { fun messages(): Iterable @@ -34,6 +33,8 @@ interface ProtobufFile : fun syntax(): String? + fun edition(): String? + fun addImport(protobufElement: ProtobufElement): Boolean fun addImport(path: String): Boolean diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufImportStatement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufImportStatement.kt new file mode 100644 index 00000000..0f15cb72 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufImportStatement.kt @@ -0,0 +1,13 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufImportStatement.public(): Boolean { + return importLabel?.textMatches("public") == true +} + +fun ProtobufImportStatement.weak(): Boolean { + return importLabel?.textMatches("weak") == true +} + +fun ProtobufImportStatement.resolve(): ProtobufFile? { + return reference?.resolve() as? ProtobufFile +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMapFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMapFieldDefinition.kt new file mode 100644 index 00000000..8899fbba --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMapFieldDefinition.kt @@ -0,0 +1,11 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufMapFieldDefinition.key(): ProtobufTypeName? { + if (typeNameList.size < 2) return null + return typeNameList[0] +} + +fun ProtobufMapFieldDefinition.value(): ProtobufTypeName? { + if (typeNameList.size < 2) return null + return typeNameList[1] +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMessageDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMessageDefinition.kt new file mode 100644 index 00000000..25a8754f --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufMessageDefinition.kt @@ -0,0 +1,137 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.firstItemOrNull +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.support.WellknownTypes +import java.util.Stack + +/** + * Resolve type of qualified field for a message definition. + * It could be returning a [ProtobufMessageDefinition] for message field. + * returning a [ProtobufEnumDefinition] for enum field. + * returning a [ProtobufMapFieldDefinition] for map field. + * returning a [ProtobufGroupDefinition] for group field. + */ +fun ProtobufMessageDefinition.resolveFieldType( + qualifiedName: QualifiedName, + jsonSpec: Boolean = false, +): ProtobufElement? { + if (qualifiedName.components.isEmpty()) return this + + val q = + Stack().apply { + addAll(qualifiedName.components.asReversed()) + } + + var scope: ProtobufScope = this + + while (q.isNotEmpty()) { + val field = q.pop() + + if (jsonSpec) { + if (scope is ProtobufMessageDefinition) { + val message = scope.qualifiedName().toString() + if (message == WellknownTypes.ANY && field == "@type") { + return scope.firstItemOrNull { + it.name() == "type_url" + } + } else if (message in WellknownTypes.types) { + return null + } + } + } + + val fieldDefinition = + scope.firstItemOrNull { + it.name() == field || it.jsonName() == field + } ?: return null + + when (fieldDefinition) { + is ProtobufFieldDefinition -> { + val type = fieldDefinition.typeName.resolve() as? ProtobufElement ?: return null + if (q.isEmpty()) return type + scope = type as? ProtobufMessageDefinition ?: return null + } + + is ProtobufMapFieldDefinition -> { + if (q.isEmpty()) return fieldDefinition + q.pop() + val type = + fieldDefinition.typeNameList.lastOrNull()?.reference?.resolve() as? ProtobufElement + ?: return null + if (q.isEmpty()) return type + scope = type as? ProtobufMessageDefinition ?: return null + } + + is ProtobufGroupDefinition -> { + scope = fieldDefinition + if (q.isEmpty()) return scope + } + } + } + return null +} + +/** + * Resolve qualified field for a message definition. + * It could be returning any [ProtobufFieldLike]. + */ +fun ProtobufMessageDefinition.resolveField( + qualifiedName: QualifiedName, + jsonSpec: Boolean = false, +): ProtobufFieldLike? { + val field = qualifiedName.lastComponent ?: return null + val parentField = qualifiedName.removeTail(1) + val parentType = resolveFieldType(parentField, jsonSpec) ?: return null + + if (jsonSpec) { + if (parentType is ProtobufMessageDefinition) { + val message = parentType.qualifiedName().toString() + if (message == WellknownTypes.ANY && field == "@type") { + return parentType.firstItemOrNull { + it.name() == "type_url" + } + } else if (message in WellknownTypes.types) { + return null + } + } + } + + return when (parentType) { + is ProtobufMessageDefinition -> { + parentType.firstItemOrNull { it.name() == field || it.jsonName() == field } + } + + is ProtobufGroupDefinition -> { + parentType.firstItemOrNull { it.name() == field || it.jsonName() == field } + } + + else -> null + } +} + +fun ProtobufFieldDefinition.repeated(): Boolean { + return this.fieldLabel?.textMatches("repeated") == true +} + +fun ProtobufGroupDefinition.repeated(): Boolean { + return this.fieldLabel?.textMatches("repeated") == true +} + +fun ProtobufFieldDefinition.required(): Boolean { + return this.fieldLabel?.textMatches("required") == true +} + +fun ProtobufGroupDefinition.required(): Boolean { + return this.fieldLabel?.textMatches("required") == true +} + +fun ProtobufFieldDefinition.optional(): Boolean { + return this.fieldLabel?.textMatches("optional") == true +} + +fun ProtobufGroupDefinition.optional(): Boolean { + return this.fieldLabel?.textMatches("optional") == true +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufOptionName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufOptionName.kt new file mode 100644 index 00000000..68d3ed89 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufOptionName.kt @@ -0,0 +1,32 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.support.Options + +fun ProtobufOptionName.field(): ProtobufFieldLike? { + return this.leaf().reference?.resolve() as? ProtobufFieldLike +} + +fun ProtobufOptionName.isFieldDefaultOption(): Boolean { + return this.textMatches("default") && parentOfType() is ProtobufFieldDefinition +} + +fun ProtobufOptionName.isFieldJsonNameOption(): Boolean { + return this.textMatches("json_name") && parentOfType() is ProtobufFieldDefinition +} + +fun ProtobufOptionName.optionType(): Options? = + when (parentOfType()) { + is ProtobufFile -> Options.FILE_OPTIONS + is ProtobufMessageDefinition, is ProtobufGroupDefinition -> Options.MESSAGE_OPTIONS + is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> Options.FIELD_OPTIONS + is ProtobufOneofDefinition -> Options.ONEOF_OPTIONS + is ProtobufEnumDefinition -> Options.ENUM_OPTIONS + is ProtobufEnumValueDefinition -> Options.ENUM_VALUE_OPTIONS + is ProtobufServiceDefinition -> Options.SERVICE_OPTIONS + is ProtobufRpcDefinition -> Options.METHOD_OPTIONS + is ProtobufExtensionRange -> Options.EXTENSION_RANGE_OPTIONS + else -> null + } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/ProtobufPsiFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufPsiFactory.kt similarity index 65% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/ProtobufPsiFactory.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufPsiFactory.kt index 9a6c8435..d759d97e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/ProtobufPsiFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufPsiFactory.kt @@ -1,13 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.util +package io.kanro.idea.plugin.protobuf.lang.psi.proto +import com.bybutter.sisyphus.string.escape import com.intellij.openapi.project.Project import com.intellij.psi.PsiFileFactory import com.intellij.psi.PsiWhiteSpace import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufStringValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName import io.kanro.idea.plugin.protobuf.lang.psi.findChild import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren @@ -38,11 +35,31 @@ object ProtobufPsiFactory { throw IllegalStateException("Wrong type name '$text'") } + fun createExtensionFieldName( + project: Project, + text: String, + ): ProtobufExtensionFieldName { + createFile(project, "option ($text) = 1;").walkChildren { + return it + } + throw IllegalStateException("Wrong extension field name '$text'") + } + + fun createFieldName( + project: Project, + text: String, + ): ProtobufFieldName { + createFile(project, "option test = { $text : 1 };").walkChildren { + return it + } + throw IllegalStateException("Wrong extension field name '$text'") + } + fun createStringValue( project: Project, text: String, ): ProtobufStringValue { - createFile(project, "import \"$text\";").walkChildren { + createFile(project, "import \"${text.escape()}\";").walkChildren { return it.stringValue!! } throw IllegalStateException("Wrong type name '$text'") diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedName.kt new file mode 100644 index 00000000..284afd48 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedName.kt @@ -0,0 +1,13 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.util.elementType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.value.decodeStringFromStringLiteral + +fun ProtobufReservedName.name(): String { + return if (firstChild.elementType == ProtobufTokens.STRING_LITERAL) { + decodeStringFromStringLiteral(firstChild) + } else { + text + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedRange.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedRange.kt new file mode 100644 index 00000000..5dcd6a31 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufReservedRange.kt @@ -0,0 +1,16 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufReservedRange.range(): LongRange? { + val numbers = integerValueList.map { it.text.toLong() } + return when (numbers.size) { + 1 -> + if (lastChild.textMatches("max")) { + LongRange(numbers[0], Long.MAX_VALUE) + } else { + LongRange(numbers[0], numbers[0]) + } + + 2 -> LongRange(numbers[0], numbers[1]) + else -> null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufRpcIO.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufRpcIO.kt new file mode 100644 index 00000000..d0d226aa --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufRpcIO.kt @@ -0,0 +1,15 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.psi.PsiElement +import com.intellij.psi.util.elementType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufKeywordToken +import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren + +fun ProtobufRpcIO.stream(): Boolean { + this.walkChildren(false) { + if (it.elementType is ProtobufKeywordToken && it.textMatches("stream")) { + return true + } + } + return false +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufStringValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufStringValue.kt new file mode 100644 index 00000000..7caa6dbf --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufStringValue.kt @@ -0,0 +1,26 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +import com.intellij.openapi.util.TextRange + +fun ProtobufStringValue.stringRange(): TextRange { + return stringRange(textRange) +} + +fun ProtobufStringValue.stringRangeInParent(): TextRange { + return stringRange(textRangeInParent) +} + +private fun ProtobufStringValue.stringRange(relativelyRange: TextRange): TextRange { + var textRange = relativelyRange + val text = text + + if (textRange.length == 0) return textRange + if (text.startsWith('"')) { + textRange = TextRange.create(textRange.startOffset + 1, textRange.endOffset) + } + if (textRange.length == 0) return textRange + if (text.endsWith('"')) { + textRange = TextRange.create(textRange.startOffset, textRange.endOffset - 1) + } + return textRange +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufTypeName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufTypeName.kt new file mode 100644 index 00000000..2bd5a73e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/ProtobufTypeName.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto + +fun ProtobufTypeName.absolutely(): Boolean { + return firstChild !is ProtobufSymbolName +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumDefinition.kt similarity index 61% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumDefinition.kt index 6b195a44..2cf31580 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumDefinition.kt @@ -1,10 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope import javax.swing.Icon interface ProtobufEnumDefinition : ProtobufNumberScope, ProtobufDefinition, ProtobufOptionOwner { @@ -21,6 +21,6 @@ interface ProtobufEnumDefinition : ProtobufNumberScope, ProtobufDefinition, Prot } override fun allowAlias(): Boolean { - return this.options("allow_alias").firstOrNull()?.value()?.booleanValue?.text == "true" + return this.options("allow_alias").firstOrNull()?.value() == true } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumValueDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumValueDefinition.kt similarity index 70% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumValueDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumValueDefinition.kt index 6ac1535d..85a3abf6 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufEnumValueDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufEnumValueDefinition.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition import javax.swing.Icon interface ProtobufEnumValueDefinition : ProtobufNumbered { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufExtendDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufExtendDefinition.kt similarity index 63% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufExtendDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufExtendDefinition.kt index 7e1333cd..f5213780 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufExtendDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufExtendDefinition.kt @@ -1,20 +1,20 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocumented -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufVirtualScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufVirtualScope import javax.swing.Icon interface ProtobufExtendDefinition : ProtobufVirtualScope, ProtobufDefinition, - ProtobufDocumented { + DocumentOwner { override fun type(): String { return "extend" } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufFieldDefinition.kt new file mode 100644 index 00000000..b6c2592f --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufFieldDefinition.kt @@ -0,0 +1,79 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element + +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.aip.AipOptions +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType +import javax.swing.Icon + +interface ProtobufFieldDefinition : ProtobufFieldLike, ProtobufMultiNameDefinition { + override fun type(): String { + return "field" + } + + override fun getIcon(unused: Boolean): Icon? { + return ProtobufIcons.FIELD + } + + fun resourceType(): String? { + if (this !is ProtobufOptionOwner) return null + return CachedValuesManager.getCachedValue(this) { + options(AipOptions.resourceReferenceOption).forEach { + it.value(AipOptions.resourceTypeField)?.toString()?.let { + return@getCachedValue CachedValueProvider.Result.create( + it, + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } + return@getCachedValue CachedValueProvider.Result.create(null, PsiModificationTracker.MODIFICATION_COUNT) + } + } + + override fun fieldValueType(): ValueType { + val typeName = findChild() ?: return ValueType.UNKNOWN + + when(typeName.text) { + BuiltInType.BOOL.value() -> return ValueType.BOOLEAN + BuiltInType.STRING.value(), + BuiltInType.BYTES.value() -> return ValueType.STRING + BuiltInType.INT32.value(), + BuiltInType.INT64.value(), + BuiltInType.UINT32.value(), + BuiltInType.UINT64.value(), + BuiltInType.FIXED32.value(), + BuiltInType.FIXED64.value(), + BuiltInType.SFIXED32.value(), + BuiltInType.SFIXED64.value(), + BuiltInType.SINT32.value(), + BuiltInType.SINT64.value(), + BuiltInType.FLOAT.value(), + BuiltInType.DOUBLE.value() -> return ValueType.NUMBER + } + + return when(typeName.resolve()) { + is ProtobufMessageDefinition -> ValueType.MESSAGE + is ProtobufEnumDefinition -> ValueType.ENUM + else -> ValueType.UNKNOWN + } + } + + override fun fieldType(): String? { + resourceType()?.let { + return it + } + return findChild()?.leaf()?.text + } + + override fun names(): Set { + return setOfNotNull(name(), jsonName()) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufGroupDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufGroupDefinition.kt similarity index 65% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufGroupDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufGroupDefinition.kt index 847a1aac..b85afefd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufGroupDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufGroupDefinition.kt @@ -1,10 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufMultiNameDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope import io.kanro.idea.plugin.protobuf.string.toCamelCase import io.kanro.idea.plugin.protobuf.string.toSnakeCase import javax.swing.Icon @@ -26,12 +27,14 @@ interface ProtobufGroupDefinition : ProtobufFieldLike, ProtobufNumberScope, Prot return identifier()?.text } + override fun fieldValueType(): ValueType = ValueType.MESSAGE + override fun name(): String? { return identifier()?.text } override fun names(): Set { val groupName = identifier()?.text ?: return emptySet() - return setOf(groupName, groupName.toSnakeCase(), groupName.toCamelCase()) + return setOf(groupName, groupName.toSnakeCase(), groupName.toCamelCase(), groupName.lowercase()) } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMapFieldDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMapFieldDefinition.kt new file mode 100644 index 00000000..27721c1e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMapFieldDefinition.kt @@ -0,0 +1,73 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element + +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.findChildren +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.string.toPascalCase +import javax.swing.Icon + +interface ProtobufMapFieldDefinition : ProtobufFieldLike, ProtobufNumberScope, ProtobufMultiNameDefinition { + fun entryName(): String? { + return "${name()} Entry".toPascalCase() + } + + override fun scope(): QualifiedName? { + return owner()?.scope()?.append(entryName()) + } + + override fun items(): Array { + return emptyArray() + } + + override fun fieldValueType(): ValueType = ValueType.MESSAGE + + fun entryFields(): Array { + val typeNames = findChildren() + val key = typeNames.getOrNull(0) + val value = typeNames.getOrNull(1) + + val keyTypeName = key?.leaf()?.text ?: "?" + val valueTypeName = value?.leaf()?.text ?: "?" + + return arrayOf( + LookupElementBuilder.create("key") + .withIcon(ProtobufIcons.FIELD) + .withTailText(": $keyTypeName = 1", true) + .withTypeText("field") + .withPsiElement(key), + LookupElementBuilder.create("value") + .withIcon(ProtobufIcons.FIELD) + .withTailText(": $valueTypeName = 2", true) + .withTypeText("field") + .withPsiElement(value), + ) + } + + override fun type(): String { + return "field" + } + + override fun getIcon(unused: Boolean): Icon? { + return ProtobufIcons.FIELD + } + + override fun fieldType(): String? { + val typeNames = findChildren() + if (typeNames.size != 2) return "map" + val key = typeNames[0].leaf().text ?: return "map" + val value = typeNames[1].leaf().text ?: return "map" + + return "map<$key, $value>" + } + + override fun names(): Set { + return setOfNotNull(name(), jsonName(), entryName()) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMessageDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMessageDefinition.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMessageDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMessageDefinition.kt index b3c2198f..dea1635c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufMessageDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufMessageDefinition.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager @@ -6,10 +6,9 @@ import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.aip.AipOptions -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufNumberScope -import io.kanro.idea.plugin.protobuf.lang.psi.stringValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufNumberScope import javax.swing.Icon interface ProtobufMessageDefinition : ProtobufNumberScope, ProtobufDefinition { @@ -35,7 +34,7 @@ interface ProtobufMessageDefinition : ProtobufNumberScope, ProtobufDefinition { if (this !is ProtobufOptionOwner) return null return CachedValuesManager.getCachedValue(this) { options(AipOptions.resourceOption).forEach { - it.value(AipOptions.resourceTypeField)?.stringValue()?.let { + it.value(AipOptions.resourceTypeField)?.toString()?.let { return@getCachedValue CachedValueProvider.Result.create( it, PsiModificationTracker.MODIFICATION_COUNT, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOneofDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOneofDefinition.kt similarity index 62% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOneofDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOneofDefinition.kt index 330247a9..a716eeff 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufOneofDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOneofDefinition.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufVirtualScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufVirtualScope import javax.swing.Icon interface ProtobufOneofDefinition : ProtobufVirtualScope, ProtobufDefinition { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOptionAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOptionAssign.kt new file mode 100644 index 00000000..d38dff36 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufOptionAssign.kt @@ -0,0 +1,18 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufConstant +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike + +interface ProtobufOptionAssign : ValueAssign { + override fun field(): ProtobufFieldLike? { + return findChild()?.leaf()?.resolve() as? ProtobufFieldLike + } + + override fun valueElement(): ValueElement<*>? { + return findChild() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufPackageName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufPackageName.kt similarity index 82% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufPackageName.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufPackageName.kt index a7d2395c..032fa8cd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufPackageName.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufPackageName.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.navigation.ItemPresentation @@ -8,19 +8,21 @@ import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocumented -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentOwner +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement import io.kanro.idea.plugin.protobuf.lang.util.doc import javax.swing.Icon interface ProtobufPackageName : - ProtobufNamedElement, - ProtobufLookupItem, - ProtobufDocumented, + NamedElement, + LookupableElement, + DocumentOwner, NavigatablePsiElement, ItemPresentation, - PsiNameIdentifierOwner { + PsiNameIdentifierOwner, + ProtobufElement { override fun name(): String? { return nameIdentifier?.text } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufRpcDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufRpcDefinition.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufRpcDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufRpcDefinition.kt index 175cffe2..38539fc3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufRpcDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufRpcDefinition.kt @@ -1,14 +1,14 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.parentOfType import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcIO -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.psi.findChild import io.kanro.idea.plugin.protobuf.lang.psi.findChildren import io.kanro.idea.plugin.protobuf.lang.psi.findLastChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcIO +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stream +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition import javax.swing.Icon interface ProtobufRpcDefinition : ProtobufDefinition { @@ -45,8 +45,8 @@ interface ProtobufRpcDefinition : ProtobufDefinition { override fun tailText(): String? { val parameters = findChildren() if (parameters.size != 2) return "()" - var input = parameters[0].typeName.symbolNameList.lastOrNull()?.text ?: return "()" - var output = parameters[1].typeName.symbolNameList.lastOrNull()?.text ?: return "()" + var input = parameters[0].typeName.leaf().text ?: return "()" + var output = parameters[1].typeName.leaf().text ?: return "()" if (parameters[0].stream()) { input = "stream $input" } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufServiceDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufServiceDefinition.kt similarity index 63% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufServiceDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufServiceDefinition.kt index d80a4a5a..d5729095 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/element/ProtobufServiceDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/element/ProtobufServiceDefinition.kt @@ -1,10 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.element +package io.kanro.idea.plugin.protobuf.lang.psi.proto.element import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope import javax.swing.Icon interface ProtobufServiceDefinition : ProtobufScope, ProtobufDefinition { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFieldAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFieldAssign.kt new file mode 100644 index 00000000..5d5aa20c --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFieldAssign.kt @@ -0,0 +1,19 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike + +interface ProtobufFieldAssign : ValueAssign { + override fun field(): ProtobufFieldLike? { + val field = findChild() ?: return null + return field.resolve() as? ProtobufFieldLike + } + + override fun valueElement(): ValueElement<*>? { + return findChild>() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFileReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFileReferenceContributor.kt new file mode 100644 index 00000000..d1f5ede9 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufFileReferenceContributor.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement + +interface ProtobufFileReferenceContributor : ProtobufElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufIndexProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufIndexProvider.kt similarity index 82% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufIndexProvider.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufIndexProvider.kt index 21a1e7ba..c5cef19a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufIndexProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufIndexProvider.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.psi.stubs.IndexSink -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub interface ProtobufIndexProvider { companion object { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionHover.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionHover.kt new file mode 100644 index 00000000..9242a87e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionHover.kt @@ -0,0 +1,40 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature + +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue + +interface ProtobufOptionHover : ProtobufElement { + fun option(): ProtobufOptionAssign? { + return findChild() + } + + fun isOption(extensionOptionName: QualifiedName): Boolean { + val option = option() ?: return false + return option.optionName.extensionFieldName?.textMatches(extensionOptionName.toString()) == true + } + + fun isOption(builtinOptionName: String): Boolean { + val option = option() ?: return false + return option.optionName.symbolName?.textMatches(builtinOptionName) == true + } + + fun value(): Any? { + return option()?.constant?.value() + } + + fun value(field: QualifiedName): Any? { + if (field.componentCount == 0) return value() + + val value = value() ?: return null + if (field.componentCount == 0) return value + + if (value is MessageValue) { + return value.value(field) + } + + return null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionOwner.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionOwner.kt similarity index 76% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionOwner.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionOwner.kt index b291e565..15df6ce3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/stratify/ProtobufOptionOwner.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufOptionOwner.kt @@ -1,12 +1,13 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement interface ProtobufOptionOwner : ProtobufElement { fun options(): Array { - return if (this is ProtobufBodyOwner) { + return if (this is BodyOwner) { body()?.findChildren() ?: arrayOf() } else { findChildren() @@ -18,7 +19,7 @@ interface ProtobufOptionOwner : ProtobufElement { */ fun options(name: QualifiedName): Array { val target = - if (this is ProtobufBodyOwner) { + if (this is BodyOwner) { body() ?: return arrayOf() } else { this @@ -34,7 +35,7 @@ interface ProtobufOptionOwner : ProtobufElement { */ fun options(name: String): Array { val target = - if (this is ProtobufBodyOwner) { + if (this is BodyOwner) { body() ?: return arrayOf() } else { this diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubExternalProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubExternalProvider.kt similarity index 81% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubExternalProvider.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubExternalProvider.kt index 33441c6c..f6b63cbd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubExternalProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubExternalProvider.kt @@ -1,7 +1,7 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature import com.intellij.openapi.extensions.ExtensionPointName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile interface ProtobufStubExternalProvider { companion object { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubSupport.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubSupport.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubSupport.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubSupport.kt index c2489066..1cf583bd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/feature/ProtobufStubSupport.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/feature/ProtobufStubSupport.kt @@ -1,8 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature +package io.kanro.idea.plugin.protobuf.lang.psi.proto.feature import com.intellij.psi.StubBasedPsiElement import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement interface ProtobufStubSupport, TPsi : ProtobufElement> : StubBasedPsiElement { fun stubData(): Array { @@ -10,7 +11,7 @@ interface ProtobufStubSupport, TPsi : ProtobufElement> } fun stubExternalData(): Map { - if (this !is ProtobufNamedElement) return mapOf() + if (this !is NamedElement) return mapOf() val result = mutableMapOf() ProtobufStubExternalProvider.extensionPoint.extensionList.forEach { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufFileImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufFileImpl.kt similarity index 78% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufFileImpl.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufFileImpl.kt index 66a4309a..b71d73fb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufFileImpl.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufFileImpl.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.impl import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.extapi.psi.PsiFileBase @@ -16,21 +16,21 @@ import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.aip.AipOptions import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSyntaxStatement import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.value -import io.kanro.idea.plugin.protobuf.lang.util.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEditionStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufSyntaxStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionHover +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope import javax.swing.Icon class ProtobufFileImpl(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, ProtobufLanguage), ProtobufFile { @@ -89,6 +89,7 @@ class ProtobufFileImpl(viewProvider: FileViewProvider) : PsiFileBase(viewProvide } "${system.getLocalByEntry(virtualFile)?.name}" } + is LocalFileSystem -> { val project = ProjectLocator.getInstance().guessProjectForFile(virtualFile) if (project != null) { @@ -101,6 +102,7 @@ class ProtobufFileImpl(viewProvider: FileViewProvider) : PsiFileBase(viewProvide } "(external)" } + else -> "(unsupported)" } } @@ -114,13 +116,19 @@ class ProtobufFileImpl(viewProvider: FileViewProvider) : PsiFileBase(viewProvide } override fun syntax(): String? { - val syntax = this.findChildByClass(ProtobufSyntaxStatement::class.java) ?: return null - val text = syntax.stringValue?.text ?: return null + val syntax = this.findChild() ?: return null + val text = syntax.stringValue?.value() ?: return null + return text.substring(1, text.length - 1) + } + + override fun edition(): String? { + val edition = this.findChild() ?: return null + val text = edition.stringValue?.value() ?: return null return text.substring(1, text.length - 1) } override fun packageParts(): Array { - return findChildByClass(ProtobufPackageStatement::class.java)?.packageNameList?.toTypedArray() ?: arrayOf() + return findChild()?.packageNameList?.toTypedArray() ?: arrayOf() } override fun resourceDefinitions(): Array { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufLineCommentImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufLineCommentImpl.kt similarity index 74% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufLineCommentImpl.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufLineCommentImpl.kt index 7118f690..ac27fe0f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/impl/ProtobufLineCommentImpl.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/impl/ProtobufLineCommentImpl.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.impl import com.intellij.lang.folding.FoldingDescriptor import com.intellij.psi.PsiElement @@ -9,12 +9,13 @@ import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker import com.intellij.refactoring.suggested.endOffset -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocument -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufFolding +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.FoldingElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement import io.kanro.idea.plugin.protobuf.lang.util.renderDoc class ProtobufLineCommentImpl(type: IElementType, text: CharSequence) : - PsiCommentImpl(type, text), ProtobufDocument, ProtobufFolding { + PsiCommentImpl(type, text), DocumentElement, FoldingElement, ProtobufElement { override fun getOwner(): PsiElement? { this.prevSibling?.let { if (it !is PsiWhiteSpace) return null @@ -31,10 +32,11 @@ class ProtobufLineCommentImpl(type: IElementType, text: CharSequence) : } override fun folding(): FoldingDescriptor? { + val range = textRange return FoldingDescriptor( this, - startOffset, - endOffset, + range.startOffset, + range.endOffset, null, "//...", ) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufEnumValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufEnumValueMixin.kt new file mode 100644 index 00000000..10fc485d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufEnumValueMixin.kt @@ -0,0 +1,17 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufEnumValueReference + +abstract class ProtobufEnumValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufEnumValue { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return arrayOf(ProtobufEnumValueReference(this)) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufExtensionFieldNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufExtensionFieldNameMixin.kt new file mode 100644 index 00000000..44f24131 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufExtensionFieldNameMixin.kt @@ -0,0 +1,49 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufExtensionFieldReference + +abstract class ProtobufExtensionFieldNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufExtensionFieldName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return arrayOf(ProtobufExtensionFieldReference(this)) + } + + override fun symbol(): QualifiedName? { + return buildList { + var parent = this@ProtobufExtensionFieldNameMixin as? ProtobufExtensionFieldName + while (parent != null) { + add(parent.symbolName.text) + parent = parent.parent as? ProtobufExtensionFieldName + } + }.reversed().let { QualifiedName.fromComponents(it) } + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtobufPsiFactory.createExtensionFieldName(project, qualifiedName.toString())) + } + + override fun leaf(): ProtobufExtensionFieldName { + var result: ProtobufExtensionFieldName = this + while (true) { + result = result.extensionFieldName ?: break + } + return result + } + + override fun root(): ProtobufExtensionFieldName { + var result: ProtobufExtensionFieldName = this + while (true) { + result = result.parent as? ProtobufExtensionFieldName ?: break + } + return result + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufFieldNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufFieldNameMixin.kt new file mode 100644 index 00000000..b27b84a5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufFieldNameMixin.kt @@ -0,0 +1,29 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufFieldReference + +abstract class ProtobufFieldNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufFieldName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return CachedValuesManager.getCachedValue(this) { + CachedValueProvider.Result( + if (symbolName != null) { + arrayOf(ProtobufFieldReference(this)) + } else { + emptyArray() + }, + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufImportStatementMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufImportStatementMixin.kt similarity index 66% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufImportStatementMixin.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufImportStatementMixin.kt index 6baee6b7..faff515f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufImportStatementMixin.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufImportStatementMixin.kt @@ -1,13 +1,13 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin import com.intellij.lang.ASTNode import com.intellij.psi.PsiReference import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufImportReference +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufImportReference abstract class ProtobufImportStatementMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufImportStatement { override fun getReference(): PsiReference { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufMessageDefinitionMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufMessageDefinitionMixin.kt similarity index 70% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufMessageDefinitionMixin.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufMessageDefinitionMixin.kt index 9889b42f..2950136f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/mixin/ProtobufMessageDefinitionMixin.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufMessageDefinitionMixin.kt @@ -1,31 +1,32 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.mixin +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin import com.intellij.lang.ASTNode import com.intellij.psi.stubs.IStubElementType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.StubBasedProtobufElementBase -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubSupport -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufExtendStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufFieldStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufGroupStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMapFieldStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufOneofStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufPackageNameStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubSupport +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.StubBasedProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufExtendStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufFieldStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufGroupStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMapFieldStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufOneofStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufPackageNameStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.string.toCamelCase abstract class ProtobufMessageDefinitionMixin : StubBasedProtobufElementBase, @@ -87,6 +88,10 @@ abstract class ProtobufGroupDefinitionMixin : constructor(stub: ProtobufGroupStub, type: IStubElementType<*, *>) : super(stub, type) + override fun fieldName(): String? { + return name()?.lowercase() + } + override fun stubData(): Array { return arrayOf(identifier?.text ?: "") } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufOptionNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufOptionNameMixin.kt new file mode 100644 index 00000000..8c4d70e0 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufOptionNameMixin.kt @@ -0,0 +1,54 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufOptionNameReference + +abstract class ProtobufOptionNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufOptionName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return if (symbolName != null) { + arrayOf(ProtobufOptionNameReference(this)) + } else { + emptyArray() + } + } + + override fun symbol(): QualifiedName? { + return null + } + + override fun rename(qualifiedName: QualifiedName) { + } + + override fun resolve(): PsiElement? { + extensionFieldName?.let { + return it.resolve() + } + + return reference?.resolve() + } + + override fun leaf(): ProtobufOptionName { + var result: ProtobufOptionName = this + while (true) { + result = result.optionName ?: break + } + return result + } + + override fun root(): ProtobufOptionName { + var result: ProtobufOptionName = this + while (true) { + result = result.parent as? ProtobufOptionName ?: break + } + return result + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufStringValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufStringValueMixin.kt new file mode 100644 index 00000000..d8b2d29d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufStringValueMixin.kt @@ -0,0 +1,27 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue + +abstract class ProtobufStringValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufStringValue { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return ReferenceProvidersRegistry.getReferencesFromProviders(this) + } + + override fun symbol(): QualifiedName? { + return value().takeIf { it.isNotEmpty() }?.let { QualifiedName.fromDottedString(it) } + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtobufPsiFactory.createStringValue(project, qualifiedName.toString())) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufTypeNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufTypeNameMixin.kt new file mode 100644 index 00000000..f98e4c1c --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/mixin/ProtobufTypeNameMixin.kt @@ -0,0 +1,49 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.reference.ProtobufTypeNameReference + +abstract class ProtobufTypeNameMixin(node: ASTNode) : ProtobufElementBase(node), ProtobufTypeName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return arrayOf(ProtobufTypeNameReference(this)) + } + + override fun symbol(): QualifiedName? { + return buildList { + var parent = this@ProtobufTypeNameMixin as? ProtobufTypeName + while (parent != null) { + add(parent.symbolName.text) + parent = parent.parent as? ProtobufTypeName + } + }.reversed().let { QualifiedName.fromComponents(it) } + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtobufPsiFactory.createTypeName(project, qualifiedName.toString())) + } + + override fun leaf(): ProtobufTypeName { + var result: ProtobufTypeName = this + while (true) { + result = result.typeName ?: break + } + return result + } + + override fun root(): ProtobufTypeName { + var result: ProtobufTypeName = this + while (true) { + result = result.parent as? ProtobufTypeName ?: break + } + return result + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufEnumValueReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufEnumValueReference.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufEnumValueReference.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufEnumValueReference.kt index bf0f4cf8..897ec8f6 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufEnumValueReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufEnumValueReference.kt @@ -1,15 +1,15 @@ -package io.kanro.idea.plugin.protobuf.lang.reference +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import com.intellij.psi.PsiReferenceBase import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.util.ArrayUtilRt -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValue -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.enum +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.enum import io.kanro.idea.plugin.protobuf.lang.psi.realItems class ProtobufEnumValueReference(field: ProtobufEnumValue) : @@ -30,7 +30,7 @@ class ProtobufEnumValueReference(field: ProtobufEnumValue) : override fun getVariants(): Array { return element.enum()?.realItems()?.mapNotNull { if (it !is ProtobufEnumValueDefinition) return@mapNotNull null - (it as? ProtobufLookupItem)?.lookup() + (it as? LookupableElement)?.lookup() }?.toTypedArray() ?: ArrayUtilRt.EMPTY_OBJECT_ARRAY } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufExtensionFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufExtensionFieldReference.kt new file mode 100644 index 00000000..b97bf566 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufExtensionFieldReference.kt @@ -0,0 +1,224 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference + +import com.intellij.codeInsight.completion.CompletionUtilCore +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.resolve.ResolveCache +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.stubs.StubIndex +import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.prev +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufField +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.absolutely +import io.kanro.idea.plugin.protobuf.lang.psi.proto.optionType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.util.or +import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix + +class ProtobufExtensionFieldReference(fieldName: ProtobufExtensionFieldName) : + PsiReferenceBase(fieldName) { + private object Resolver : ResolveCache.Resolver { + override fun resolve( + ref: PsiReference, + incompleteCode: Boolean, + ): PsiElement? { + ref as ProtobufExtensionFieldReference + + val extendMessage = ref.extendMessage() ?: return null + val qualifiedName = ref.element.leaf().symbol() ?: return null + return if (ref.element.absolutely()) { + ProtobufSymbolResolver.resolveAbsolutely( + ref.element, + qualifiedName, + ProtobufSymbolFilters.extensionField(extendMessage), + ) + } else { + ProtobufSymbolResolver.resolveRelatively( + ref.element, + qualifiedName, + ProtobufSymbolFilters.extensionField(extendMessage), + ) + } + } + } + + override fun resolve(): PsiElement? { + element.extensionFieldName?.let { + return when (val item = it.reference?.resolve()) { + is ProtobufScopeItem -> { + when (val owner = item.owner()) { + is ProtobufFile -> owner.packageParts().lastOrNull() + else -> owner + } + } + + is ProtobufPackageName -> item.prev() + else -> null + } + } + + return ResolveCache.getInstance(element.project).resolveWithCaching(this, Resolver, false, false) + } + + override fun getCanonicalText(): String { + return element.text + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.symbolName.textRangeInParent + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.symbolName.identifierLiteral as? LeafPsiElement)?.replaceWithText(newElementName) + return element + } + + private fun extendMessage(): QualifiedName? { + val host = element.root().parent ?: return null + return when (host) { + is ProtobufOptionName -> { + return when (val parent = host.parent) { + is ProtobufOptionName -> { + val field = parent.resolve() as? ProtobufFieldDefinition ?: return null + val message = field.typeName.resolve() as? ProtobufMessageDefinition ?: return null + message.qualifiedName() + } + + is ProtobufOptionAssign -> { + val optionType = host.optionType() ?: return null + optionType.qualifiedName + } + + else -> null + } + + } + + is ProtobufExtensionName -> { + val assign = host.parentOfType()?.parentOfType() ?: return null + return when (val field = assign.field()) { + is ProtobufGroupDefinition -> field.scope() + is ProtobufFieldDefinition -> (field.typeName.resolve() as? ProtobufMessageDefinition)?.qualifiedName() + else -> null + } + } + + else -> null + } + } + + override fun getVariants(): Array { + val result = mutableListOf() + val addedElements = mutableSetOf() + val extendMessage = extendMessage() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + val filter = ProtobufSymbolFilters.extensionField(extendMessage) + + getVariantsInCurrentScope(filter or ProtobufSymbolFilters.packageName, result, addedElements) + getVariantsInStubIndex(filter, result, addedElements) + return result.toTypedArray() + } + + private fun getVariantsInCurrentScope( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ) { + val parentScope = element.symbol() ?: return + ProtobufSymbolResolver.collectAbsolute(element, parentScope, filter).forEach { + if (it in elements) return@forEach + result += lookupFor(it, parentScope) ?: return@forEach + elements += it + } + } + + private fun getVariantsInStubIndex( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ): Array { + if (element.parent is ProtobufExtensionFieldName) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (element.extensionFieldName != null) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (!element.text.endsWith(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED)) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + + val searchName = element.text.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) + val scope = ProtobufRootResolver.searchScope(element) + val matcher = PlatformPatterns.string().contains(searchName) + val currentScope = element.parentOfType()?.scope() + + return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { + matcher.accepts(it) + }.flatMap { + StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) + .asSequence() + }.filter { + filter.isAccepted(it) + }.mapNotNull { + if (it in elements) return@mapNotNull null + result += lookupForStub(it, currentScope) ?: return@mapNotNull null + elements += it + }.toList().toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + var builder = (element as? LookupableElement)?.lookup() ?: return null + builder = builder.withLookupString(scope.append(builder.lookupString).toString()) + if (element is ProtobufPackageName) { + builder = builder.withInsertHandler(packageInsertHandler) + } + return builder + } + + private fun lookupForStub( + element: ProtobufElement, + currentScope: QualifiedName?, + ): LookupElement? { + if (element !is ProtobufDefinition) return null + val qualifiedName = element.qualifiedName() ?: return null + + val targetName = + if (currentScope != null) { + qualifiedName.removeCommonPrefix(currentScope) + } else { + qualifiedName + } + return LookupElementBuilder.create(targetName).withLookupString(qualifiedName.lastComponent!!) + .withPresentableText(qualifiedName.lastComponent!!).withIcon(element.getIcon(false)) + .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) + .withTypeText(element.type()).withInsertHandler(AddImportInsertHandler(element)) + } + + companion object { + private val packageInsertHandler = SmartInsertHandler(".", 0, true) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufFieldReference.kt new file mode 100644 index 00000000..a67b800e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufFieldReference.kt @@ -0,0 +1,79 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.key +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ownerMessage +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.value +import io.kanro.idea.plugin.protobuf.lang.psi.realItems + +class ProtobufFieldReference(field: ProtobufFieldName) : + PsiReferenceBase(field) { + override fun resolve(): PsiElement? { + val message = element.ownerMessage() ?: return null + if (message is ProtobufMapFieldDefinition) { + when (element.text) { + "key" -> return message.key() + "value" -> return message.value() + } + } + message.items { + if (it.fieldName() == element.text) { + return it + } + } + return null + } + + override fun calculateDefaultRangeInElement(): TextRange { + return TextRange.create(0, element.textLength) + } + + override fun getVariants(): Array { + val message = element.ownerMessage() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (message is ProtobufMapFieldDefinition) { + return message.entryFields().map { + when (it.psiElement?.reference?.resolve()) { + is ProtobufGroupDefinition, + is ProtobufMessageDefinition, + -> it.withInsertHandler(messageFieldInsertHandler) + + else -> it.withInsertHandler(fieldInsertHandler) + } + }.toTypedArray() + } + return message.realItems().mapNotNull { + (it as? ProtobufFieldLike)?.lookup()?.let { + when (it.psiElement?.reference?.resolve()) { + is ProtobufGroupDefinition, + is ProtobufMessageDefinition, + -> it.withInsertHandler(messageFieldInsertHandler) + + else -> it.withInsertHandler(fieldInsertHandler) + } + } + }.toTypedArray() + } + + override fun handleElementRename(newElementName: String): PsiElement { + ProtobufPsiFactory.createFieldName(element.project, newElementName).let { + return element.replace(it) + } + } + + companion object { + private val fieldInsertHandler = SmartInsertHandler(": ") + + private val messageFieldInsertHandler = SmartInsertHandler(" {}", -1) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufImportReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufImportReference.kt similarity index 92% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufImportReference.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufImportReference.kt index 633fd5d6..599da48f 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufImportReference.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufImportReference.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.reference +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference import com.intellij.codeInsight.lookup.AutoCompletionPolicy import com.intellij.codeInsight.lookup.LookupElement @@ -13,11 +13,10 @@ import com.intellij.psi.impl.source.resolve.ResolveCache import com.intellij.util.ArrayUtilRt import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufImportStatement -import io.kanro.idea.plugin.protobuf.lang.psi.stringRangeInParent -import io.kanro.idea.plugin.protobuf.lang.psi.value +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufImportStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stringRangeInParent import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver -import io.kanro.idea.plugin.protobuf.lang.util.ProtobufPsiFactory class ProtobufImportReference(import: ProtobufImportStatement) : PsiReferenceBase(import) { private object Resolver : ResolveCache.Resolver { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufOptionNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufOptionNameReference.kt new file mode 100644 index 00000000..675965c9 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufOptionNameReference.kt @@ -0,0 +1,138 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference + +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.resolve.ResolveCache +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.optionType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.realItems +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.support.Options + +class ProtobufOptionNameReference(optionName: ProtobufOptionName) : PsiReferenceBase(optionName) { + private object Resolver : ResolveCache.Resolver { + override fun resolve( + ref: PsiReference, + incompleteCode: Boolean, + ): PsiElement? { + ref as ProtobufOptionNameReference + val search = ref.element.symbolName?.text ?: return null + val message = ref.ownerMessage() ?: return null + + if (message.scope() == Options.FIELD_OPTIONS.qualifiedName) { + if (search == "default") { + return ref.element.parentOfType() + } + if (search == "json_name") { + return ProtobufSymbolResolver.resolveAbsolutelyInFile( + ref.descriptor() ?: return null, + QualifiedName.fromDottedString("google.protobuf.FieldDescriptorProto.json_name"), + ) + } + } + + message.items { + if (it.fieldName() == search) { + return it + } + } + + return null + } + } + + override fun resolve(): PsiElement? { + return ResolveCache.getInstance(element.project).resolveWithCaching(this, Resolver, false, false) + } + + private fun descriptor(): ProtobufFile? { + return ProtobufRootResolver.findFile("google/protobuf/descriptor.proto", element).firstOrNull()?.let { + PsiManager.getInstance(element.project).findFile(it) as? ProtobufFile + } + } + + private fun ownerMessage(): ProtobufScope? { + when (val parent = element.parent) { + is ProtobufOptionAssign -> { + return ProtobufSymbolResolver.resolveAbsolutelyInFile( + descriptor() ?: return null, + element.optionType()?.qualifiedName ?: return null, + ) as? ProtobufScope ?: return null + } + + is ProtobufOptionName -> { + return when (val field = parent.resolve() as? ProtobufFieldLike) { + is ProtobufGroupDefinition -> field + is ProtobufFieldDefinition -> field.typeName.resolve() as? ProtobufScope + else -> null + } + } + + else -> return null + } + } + + override fun getCanonicalText(): String { + return element.text + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.symbolName?.textRangeInParent ?: TextRange.EMPTY_RANGE + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.symbolName?.identifierLiteral as? LeafPsiElement)?.replaceWithText(newElementName) + return element + } + + override fun getVariants(): Array { + val message = ownerMessage() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + val result = + message.realItems().mapNotNull { + (it as? ProtobufFieldDefinition)?.lookup()?.let { + when (it.psiElement?.reference?.resolve()) { + is ProtobufGroupDefinition, + is ProtobufMessageDefinition, + -> it + + else -> it.withInsertHandler(fieldInsertHandler) + } + } + }.toMutableList() + + if (Options.FIELD_OPTIONS.qualifiedName == message.scope()) { + result += + LookupElementBuilder.create("default").withTypeText("option").withIcon(ProtobufIcons.FIELD) + .withInsertHandler(fieldInsertHandler) + result += + LookupElementBuilder.create("json_name").withTypeText("option").withIcon(ProtobufIcons.FIELD) + .withInsertHandler(fieldInsertHandler) + } + + return result.toTypedArray() + } + + companion object { + private val fieldInsertHandler = SmartInsertHandler(" = ") + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufTypeNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufTypeNameReference.kt new file mode 100644 index 00000000..e54b3129 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/reference/ProtobufTypeNameReference.kt @@ -0,0 +1,191 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.reference + +import com.intellij.codeInsight.completion.CompletionUtilCore +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.resolve.ResolveCache +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.stubs.StubIndex +import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.prev +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.absolutely +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.util.or +import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix + +class ProtobufTypeNameReference(typeName: ProtobufTypeName) : PsiReferenceBase(typeName) { + private object Resolver : ResolveCache.Resolver { + override fun resolve( + ref: PsiReference, + incompleteCode: Boolean, + ): PsiElement? { + ref as ProtobufTypeNameReference + val qualifiedName = ref.element.leaf().symbol() ?: return null + return if (ref.element.absolutely()) { + ProtobufSymbolResolver.resolveAbsolutely( + ref.element, + qualifiedName, + ref.filter(), + ) + } else { + ProtobufSymbolResolver.resolveRelatively( + ref.element, + qualifiedName, + ref.filter(), + ) + } + } + } + + private fun filter(): PsiElementFilter { + return when (element.root().parent) { + is ProtobufMapFieldDefinition, + is ProtobufFieldDefinition, + -> ProtobufSymbolFilters.fieldType + + is ProtobufExtendDefinition -> ProtobufSymbolFilters.extendMessage + + else -> ProtobufSymbolFilters.message + } + } + + override fun resolve(): PsiElement? { + element.typeName?.let { + return when (val item = it.reference?.resolve()) { + is ProtobufScopeItem -> { + when (val owner = item.owner()) { + is ProtobufFile -> owner.packageParts().lastOrNull() + else -> owner + } + } + + is ProtobufPackageName -> item.prev() + else -> null + } + } + + return ResolveCache.getInstance(element.project).resolveWithCaching(this, Resolver, false, false) + } + + override fun getCanonicalText(): String { + return element.text + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.symbolName.textRangeInParent + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.symbolName.identifierLiteral as? LeafPsiElement)?.replaceWithText(newElementName) + return element + } + + override fun getVariants(): Array { + val result = mutableListOf() + val addedElements = mutableSetOf() + val filter = filter() or ProtobufSymbolFilters.packageName + getVariantsInCurrentScope(filter, result, addedElements) + getVariantsInStubIndex(filter, result, addedElements) + return result.toTypedArray() + } + + private fun getVariantsInCurrentScope( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ) { + val parentScope = element.symbol() ?: return + ProtobufSymbolResolver.collectAbsolute(element, parentScope, filter).forEach { + if (it in elements) return@forEach + result += lookupFor(it, parentScope) ?: return@forEach + elements += it + } + } + + private fun getVariantsInStubIndex( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ): Array { + if (element.parent is ProtobufTypeName) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (element.typeName != null) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (!element.text.endsWith(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED)) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + + val searchName = element.text.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) + val scope = ProtobufRootResolver.searchScope(element) + val matcher = PlatformPatterns.string().contains(searchName) + val currentScope = element.parentOfType()?.scope() + + return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { + matcher.accepts(it) + }.flatMap { + StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) + .asSequence() + }.filter { + filter.isAccepted(it) + }.mapNotNull { + if (it in elements) return@mapNotNull null + result += lookupForStub(it, currentScope) ?: return@mapNotNull null + elements += it + }.toList().toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + var builder = (element as? LookupableElement)?.lookup() ?: return null + builder = builder.withLookupString(scope.append(builder.lookupString).toString()) + if (element is ProtobufPackageName) { + builder = builder.withInsertHandler(packageInsertHandler) + } + return builder + } + + private fun lookupForStub( + element: ProtobufElement, + currentScope: QualifiedName?, + ): LookupElement? { + if (element !is ProtobufDefinition) return null + val qualifiedName = element.qualifiedName() ?: return null + + val targetName = + if (currentScope != null) { + qualifiedName.removeCommonPrefix(currentScope) + } else { + qualifiedName + } + return LookupElementBuilder.create(targetName).withLookupString(qualifiedName.lastComponent!!) + .withPresentableText(qualifiedName.lastComponent!!).withIcon(element.getIcon(false)) + .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) + .withTypeText(element.type()).withInsertHandler(AddImportInsertHandler(element)) + } + + companion object { + private val packageInsertHandler = SmartInsertHandler(".", 0, true) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufDefinition.kt similarity index 83% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufDefinition.kt index 71d98d83..a168cce1 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufDefinition.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.navigation.ItemPresentation @@ -7,20 +7,20 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.impl.source.tree.LeafElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentOwner +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement import io.kanro.idea.plugin.protobuf.lang.psi.findChild -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocumented -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier import io.kanro.idea.plugin.protobuf.lang.util.doc import javax.swing.Icon interface ProtobufDefinition : ProtobufScopeItem, PsiNameIdentifierOwner, - ProtobufNamedElement, - ProtobufLookupItem, - ProtobufDocumented, + NamedElement, + LookupableElement, + DocumentOwner, NavigatablePsiElement, ItemPresentation { fun type(): String diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufFieldLike.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufFieldLike.kt new file mode 100644 index 00000000..5a76bf4a --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufFieldLike.kt @@ -0,0 +1,36 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure + +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ProtobufNumbered +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.string.toCamelCase + +interface ProtobufFieldLike : ProtobufDefinition, ProtobufNumbered { + fun fieldName(): String? { + return name() + } + + fun fieldType(): String? + + fun fieldValueType(): ValueType + + fun jsonName(): String? { + return CachedValuesManager.getCachedValue(this) { + val option = (this as? ProtobufOptionOwner)?.options("json_name")?.lastOrNull() + val result = + option?.value()?.toString() + ?: fieldName()?.toCamelCase() + CachedValueProvider.Result.create( + result, + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } + + override fun tailText(): String? { + return ": ${fieldType()} = ${number()}" + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufMultiNameDefinition.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufMultiNameDefinition.kt similarity index 58% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufMultiNameDefinition.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufMultiNameDefinition.kt index 0240748c..434708aa 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufMultiNameDefinition.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufMultiNameDefinition.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure interface ProtobufMultiNameDefinition : ProtobufDefinition { fun names(): Set diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumberScope.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufNumberScope.kt similarity index 50% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumberScope.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufNumberScope.kt index cd818d47..ffb6145a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufNumberScope.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufNumberScope.kt @@ -1,14 +1,15 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionStatement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedRange -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedStatement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtensionStatement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedRange +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedStatement interface ProtobufNumberScope : ProtobufScope { fun reservedRange(): Array { - return if (this is ProtobufBodyOwner) { + return if (this is BodyOwner) { this.body()?.findChildren() ?: arrayOf() } else { findChildren() @@ -17,13 +18,13 @@ interface ProtobufNumberScope : ProtobufScope { }.toTypedArray() } - fun extensionRange(): Array { - return if (this is ProtobufBodyOwner) { + fun extensionRange(): Array { + return if (this is BodyOwner) { this.body()?.findChildren() ?: arrayOf() } else { findChildren() }.flatMap { - it.reservedRangeList + it.extensionRangeList }.toTypedArray() } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScope.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScope.kt similarity index 58% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScope.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScope.kt index 83dfaef0..898d7ed7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScope.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScope.kt @@ -1,16 +1,16 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufReservedStatement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufReservedStatement interface ProtobufScope : ProtobufScopeItemContainer, ProtobufScopeItem { fun scope(): QualifiedName? fun reservedNames(): Array { - return if (this is ProtobufBodyOwner) { + return if (this is BodyOwner) { this.body()?.findChildren() ?: arrayOf() } else { findChildren() diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItem.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItem.kt similarity index 54% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItem.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItem.kt index 571405e9..5521776c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItem.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItem.kt @@ -1,7 +1,7 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement interface ProtobufScopeItem : ProtobufElement { fun owner(): ProtobufScope? { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItemContainer.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItemContainer.kt similarity index 50% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItemContainer.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItemContainer.kt index a590c9c7..19ae5bf2 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/structure/ProtobufScopeItemContainer.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufScopeItemContainer.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure +import io.kanro.idea.plugin.protobuf.lang.psi.feature.BodyOwner import io.kanro.idea.plugin.protobuf.lang.psi.findChildren -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufBodyOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement interface ProtobufScopeItemContainer : ProtobufElement { fun items(): Array { - return if (this is ProtobufBodyOwner) { + return if (this is BodyOwner) { this.body()?.findChildren() ?: arrayOf() } else { findChildren() diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufVirtualScope.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufVirtualScope.kt new file mode 100644 index 00000000..8be30e08 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/structure/ProtobufVirtualScope.kt @@ -0,0 +1,3 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.structure + +interface ProtobufVirtualScope : ProtobufScopeItemContainer diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/ProtobufStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/ProtobufStub.kt similarity index 85% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/ProtobufStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/ProtobufStub.kt index a6e8614f..5b1add0e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/ProtobufStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/ProtobufStub.kt @@ -1,8 +1,7 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile -import com.intellij.psi.StubBuilder import com.intellij.psi.stubs.DefaultStubBuilder import com.intellij.psi.stubs.PsiFileStub import com.intellij.psi.stubs.StubElement @@ -10,9 +9,9 @@ import com.intellij.psi.stubs.StubInputStream import com.intellij.psi.stubs.StubOutputStream import com.intellij.psi.tree.IStubFileElementType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufFileStubImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufFileStubImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub interface ProtobufStub : StubElement { fun data(index: Int): String @@ -22,7 +21,10 @@ interface ProtobufStub : StubElement { fun writeTo(dataStream: StubOutputStream) } -interface ProtobufFileStub : PsiFileStub, ProtobufStub, ProtobufScopeStub { +interface ProtobufFileStub : + PsiFileStub, + ProtobufStub, + ProtobufScopeStub { object Type : IStubFileElementType("PROTO_FILE", ProtobufLanguage) { override fun getStubVersion(): Int { return 1 diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/StubBasedProtobufElementBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/StubBasedProtobufElementBase.kt similarity index 78% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/StubBasedProtobufElementBase.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/StubBasedProtobufElementBase.kt index f5d68a0e..a62048df 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/primitive/StubBasedProtobufElementBase.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/StubBasedProtobufElementBase.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.primitive +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub import com.intellij.extapi.psi.StubBasedPsiElementBase import com.intellij.lang.ASTNode import com.intellij.navigation.ItemPresentation import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.psi.stubs.IStubElementType -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufStubBase +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufStubBase abstract class StubBasedProtobufElementBase> : StubBasedPsiElementBase { constructor(node: ASTNode) : super(node) @@ -29,7 +29,7 @@ abstract class StubBasedProtobufElementBase> : StubBased } override fun getName(): String? { - if (this is ProtobufNamedElement) return name() + if (this is NamedElement) return name() return null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumStub.kt similarity index 54% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumStub.kt index 5f4352be..4c3658eb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumStub.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufEnumStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufEnumStubType class ProtobufEnumStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumValueStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumValueStub.kt similarity index 52% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumValueStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumValueStub.kt index 8db09e0d..c414c3ea 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufEnumValueStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufEnumValueStub.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufEnumValueStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufEnumValueStubType class ProtobufEnumValueStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufExtendStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufExtendStub.kt new file mode 100644 index 00000000..688ee78e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufExtendStub.kt @@ -0,0 +1,15 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl + +import com.intellij.psi.stubs.StubElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufVirtualScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufExtendStubType + +class ProtobufExtendStub( + data: Array, + external: Map, + parent: StubElement<*>?, +) : ProtobufStubBase(data, external, parent, ProtobufExtendStubType), + ProtobufStub, + ProtobufVirtualScopeStub diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFieldStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFieldStub.kt similarity index 52% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFieldStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFieldStub.kt index e76b7ed2..977cd541 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFieldStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFieldStub.kt @@ -1,10 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufFieldStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufFieldStubType class ProtobufFieldStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFileStubImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFileStubImpl.kt similarity index 71% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFileStubImpl.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFileStubImpl.kt index 526cdee8..2e0d9cfb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufFileStubImpl.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufFileStubImpl.kt @@ -1,12 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.PsiFileStubImpl import com.intellij.psi.stubs.StubOutputStream import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.writeMap -import io.kanro.idea.plugin.protobuf.lang.psi.stub.writeStringArray +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.writeMap +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.writeStringArray class ProtobufFileStubImpl( file: ProtobufFile?, @@ -14,7 +13,7 @@ class ProtobufFileStubImpl( private val external: Map = file?.stubExternalData() ?: mapOf(), ) : PsiFileStubImpl(file), - ProtobufFileStub { + io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub { override fun scope(): QualifiedName { return QualifiedName.fromComponents(childrenStubs.filterIsInstance().map { it.name() }) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufGroupStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufGroupStub.kt similarity index 54% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufGroupStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufGroupStub.kt index d41ec771..494b6681 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufGroupStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufGroupStub.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufGroupStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufGroupStubType class ProtobufGroupStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMapFieldStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMapFieldStub.kt similarity index 52% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMapFieldStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMapFieldStub.kt index b51e4d4d..7eae0579 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMapFieldStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMapFieldStub.kt @@ -1,10 +1,10 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufMapFieldStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufMapFieldStubType class ProtobufMapFieldStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMessageStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMessageStub.kt similarity index 58% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMessageStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMessageStub.kt index 28bda162..090b4230 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufMessageStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufMessageStub.kt @@ -1,12 +1,12 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufMessageStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufMessageStubType class ProtobufMessageStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufOneofStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufOneofStub.kt new file mode 100644 index 00000000..c8a9d5b8 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufOneofStub.kt @@ -0,0 +1,20 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl + +import com.intellij.psi.stubs.StubElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufVirtualScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufOneofStubType + +class ProtobufOneofStub( + data: Array, + external: Map, + parent: StubElement<*>?, +) : ProtobufStubBase(data, external, parent, ProtobufOneofStubType), + io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub, + ProtobufDefinitionStub, + ProtobufVirtualScopeStub { + override fun name(): String? { + return data(0).takeIf { it.isNotEmpty() } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufPackageNameStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufPackageNameStub.kt similarity index 52% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufPackageNameStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufPackageNameStub.kt index 66c35c25..698517cf 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufPackageNameStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufPackageNameStub.kt @@ -1,16 +1,15 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufPackageNameStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufPackageNameStubType class ProtobufPackageNameStub( data: Array, external: Map, parent: StubElement<*>?, ) : ProtobufStubBase(data, external, parent, ProtobufPackageNameStubType), - ProtobufStub { + io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub { fun name(): String? { return data(0).takeIf { it.isNotEmpty() } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufRpcStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufRpcStub.kt similarity index 51% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufRpcStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufRpcStub.kt index b178aa48..b297f3a0 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufRpcStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufRpcStub.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufRpcStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufRpcStubType class ProtobufRpcStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufServiceStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufServiceStub.kt similarity index 51% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufServiceStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufServiceStub.kt index 5a0a2b9a..a31f93a2 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufServiceStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufServiceStub.kt @@ -1,14 +1,14 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.QualifiedName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufServiceStubType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufScopeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufServiceStubType class ProtobufServiceStub( data: Array, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufStubBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufStubBase.kt similarity index 70% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufStubBase.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufStubBase.kt index 05da6172..9dec60f8 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufStubBase.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/impl/ProtobufStubBase.kt @@ -1,20 +1,19 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl import com.intellij.psi.PsiElement import com.intellij.psi.stubs.IStubElementType import com.intellij.psi.stubs.StubBase import com.intellij.psi.stubs.StubElement import com.intellij.psi.stubs.StubOutputStream -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.writeMap -import io.kanro.idea.plugin.protobuf.lang.psi.stub.writeStringArray +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.writeMap +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.writeStringArray abstract class ProtobufStubBase( private val data: Array, private val externalData: Map, parent: StubElement<*>?, type: IStubElementType<*, *>, -) : StubBase(parent, type), ProtobufStub { +) : StubBase(parent, type), io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub { override fun data(index: Int): String { return data[index] } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/QualifiedNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/QualifiedNameIndex.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/QualifiedNameIndex.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/QualifiedNameIndex.kt index 6884f9ff..3432a015 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/QualifiedNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/QualifiedNameIndex.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.index +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class QualifiedNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ResourceTypeIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ResourceTypeIndex.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ResourceTypeIndex.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ResourceTypeIndex.kt index 5fa1b243..3d519adb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ResourceTypeIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ResourceTypeIndex.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.index +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class ResourceTypeIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ShortNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ShortNameIndex.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ShortNameIndex.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ShortNameIndex.kt index 8e16e47c..3687d8c3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/index/ShortNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/index/ShortNameIndex.kt @@ -1,8 +1,8 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.index +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class ShortNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/primitive/ProtobufNamedStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/primitive/ProtobufNamedStub.kt similarity index 94% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/primitive/ProtobufNamedStub.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/primitive/ProtobufNamedStub.kt index 9b956064..b41fdabb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/primitive/ProtobufNamedStub.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/primitive/ProtobufNamedStub.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive import com.intellij.psi.stubs.Stub import com.intellij.psi.util.QualifiedName diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumStubType.kt index 849e8f96..a28dd35b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufEnumDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufEnumDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub object ProtobufEnumStubType : ProtobufStubTypeBase( "ENUM_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumValueStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumValueStubType.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumValueStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumValueStubType.kt index bcb2a80b..df529472 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufEnumValueStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufEnumValueStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufEnumValueDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufEnumValueDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub object ProtobufEnumValueStubType : ProtobufStubTypeBase( "ENUM_VALUE_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufExtendStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufExtendStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufExtendStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufExtendStubType.kt index 5334ed3b..c80c1a7c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufExtendStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufExtendStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufExtendDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufExtendStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufExtendDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufExtendStub object ProtobufExtendStubType : ProtobufStubTypeBase( "EXTEND_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufFieldStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufFieldStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufFieldStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufFieldStubType.kt index 16b181b2..df17a1f3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufFieldStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufFieldStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufFieldDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufFieldStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufFieldDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufFieldStub object ProtobufFieldStubType : ProtobufStubTypeBase( "FIELD_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufGroupStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufGroupStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufGroupStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufGroupStubType.kt index 6accdb3e..20f8f3af 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufGroupStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufGroupStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufGroupDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufGroupStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufGroupDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufGroupStub object ProtobufGroupStubType : ProtobufStubTypeBase( "GROUP_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMapFieldStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMapFieldStubType.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMapFieldStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMapFieldStubType.kt index d9a50ce1..9226ea7b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMapFieldStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMapFieldStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufMapFieldDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMapFieldStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufMapFieldDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMapFieldStub object ProtobufMapFieldStubType : ProtobufStubTypeBase( "MAP_FIELD_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMessageStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMessageStubType.kt similarity index 70% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMessageStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMessageStubType.kt index 710e14ce..ebea2d57 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufMessageStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufMessageStubType.kt @@ -1,11 +1,11 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.IndexSink import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufMessageDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ResourceTypeIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufMessageDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ResourceTypeIndex object ProtobufMessageStubType : ProtobufStubTypeBase( "MESSAGE_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufOneofStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufOneofStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufOneofStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufOneofStubType.kt index 3da28d13..6b1a70a7 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufOneofStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufOneofStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufOneofDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufOneofStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufOneofDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufOneofStub object ProtobufOneofStubType : ProtobufStubTypeBase( "ONEOF_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufPackageNameStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufPackageNameStubType.kt similarity index 68% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufPackageNameStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufPackageNameStubType.kt index e70b21be..31854610 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufPackageNameStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufPackageNameStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufPackageNameImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufPackageNameStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufPackageNameImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufPackageNameStub object ProtobufPackageNameStubType : ProtobufStubTypeBase( "PACKAGE_NAME", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufRpcStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufRpcStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufRpcStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufRpcStubType.kt index a5de8d8f..cbf368f3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufRpcStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufRpcStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufRpcDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufRpcDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub object ProtobufRpcStubType : ProtobufStubTypeBase( "RPC_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufServiceStubType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufServiceStubType.kt similarity index 67% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufServiceStubType.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufServiceStubType.kt index b3e2bf47..290d1854 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufServiceStubType.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufServiceStubType.kt @@ -1,9 +1,9 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.impl.ProtobufServiceDefinitionImpl -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.impl.ProtobufServiceDefinitionImpl +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub object ProtobufServiceStubType : ProtobufStubTypeBase( "SERVICE_DEFINITION", diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypeBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypeBase.kt similarity index 71% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypeBase.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypeBase.kt index a334cad5..c4c8cccb 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypeBase.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypeBase.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.PsiElement import com.intellij.psi.stubs.IStubElementType @@ -7,14 +7,14 @@ import com.intellij.psi.stubs.StubElement import com.intellij.psi.stubs.StubInputStream import com.intellij.psi.stubs.StubOutputStream import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufIndexProvider -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufStubSupport -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufStubBase -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ShortNameIndex -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.readMap -import io.kanro.idea.plugin.protobuf.lang.psi.stub.readStringArray +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufIndexProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufStubSupport +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufStubBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufDefinitionStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.readMap +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.readStringArray abstract class ProtobufStubTypeBase, TPsi : PsiElement>( name: String, diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypes.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypes.kt similarity index 96% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypes.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypes.kt index 92c4a9da..0656b77a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/type/ProtobufStubTypes.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/stub/type/ProtobufStubTypes.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.type +package io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type import com.intellij.psi.tree.IElementType diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufCommentToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufCommentToken.kt similarity index 76% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufCommentToken.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufCommentToken.kt index 9520e058..e3a277c4 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufCommentToken.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufCommentToken.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.token +package io.kanro.idea.plugin.protobuf.lang.psi.proto.token import com.intellij.psi.tree.IElementType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufKeywordToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufKeywordToken.kt similarity index 76% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufKeywordToken.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufKeywordToken.kt index 1c0252c8..13f1c884 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufKeywordToken.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufKeywordToken.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.token +package io.kanro.idea.plugin.protobuf.lang.psi.proto.token import com.intellij.psi.tree.IElementType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufToken.kt similarity index 75% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufToken.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufToken.kt index 51051062..9b4a6896 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufToken.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufToken.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.token +package io.kanro.idea.plugin.protobuf.lang.psi.proto.token import com.intellij.psi.tree.IElementType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufTokens.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufTokens.kt similarity index 95% rename from src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufTokens.kt rename to src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufTokens.kt index cc0bd1c8..a287b0dd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/token/ProtobufTokens.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/proto/token/ProtobufTokens.kt @@ -1,4 +1,4 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.token +package io.kanro.idea.plugin.protobuf.lang.psi.proto.token import com.intellij.psi.tree.IElementType @@ -52,6 +52,9 @@ object ProtobufTokens { @JvmField val MINUS = put(ProtobufToken("-")) + @JvmField + val PLUS = put(ProtobufToken("+")) + @JvmField val RBRACE = put(ProtobufToken("}")) @@ -106,6 +109,9 @@ object ProtobufTokens { @JvmField val EXTENSIONS = put(ProtobufKeywordToken("extensions")) + @JvmField + val EDITION = put(ProtobufKeywordToken("edition")) + @JvmField val FALSE = put(ProtobufKeywordToken("false")) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufExtendStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufExtendStub.kt deleted file mode 100644 index c5b8f32d..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufExtendStub.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl - -import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufVirtualScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufExtendStubType - -class ProtobufExtendStub( - data: Array, - external: Map, - parent: StubElement<*>?, -) : ProtobufStubBase(data, external, parent, ProtobufExtendStubType), - ProtobufStub, - ProtobufVirtualScopeStub diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufOneofStub.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufOneofStub.kt deleted file mode 100644 index 967a8c29..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/stub/impl/ProtobufOneofStub.kt +++ /dev/null @@ -1,21 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.psi.stub.impl - -import com.intellij.psi.stubs.StubElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufDefinitionStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufVirtualScopeStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.type.ProtobufOneofStubType - -class ProtobufOneofStub( - data: Array, - external: Map, - parent: StubElement<*>?, -) : ProtobufStubBase(data, external, parent, ProtobufOneofStubType), - ProtobufStub, - ProtobufDefinitionStub, - ProtobufVirtualScopeStub { - override fun name(): String? { - return data(0).takeIf { it.isNotEmpty() } - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextASTFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextASTFactory.kt new file mode 100644 index 00000000..4b859a6c --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextASTFactory.kt @@ -0,0 +1,21 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.lang.DefaultASTFactoryImpl +import com.intellij.psi.impl.source.tree.LeafElement +import com.intellij.psi.impl.source.tree.PsiCommentImpl +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.psi.text.token.ProtoTextTokens + +class ProtoTextASTFactory : DefaultASTFactoryImpl() { + override fun createComment( + type: IElementType, + text: CharSequence, + ): LeafElement { + return if (type == ProtoTextTokens.SHARP_LINE_COMMENT) { + ProtoTextSharpLineCommentImpl(type, text) + } else { + PsiCommentImpl(type, text) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElement.kt new file mode 100644 index 00000000..f6a3596e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElement.kt @@ -0,0 +1,17 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import io.kanro.idea.plugin.protobuf.lang.psi.BaseElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile + +interface ProtoTextElement : BaseElement { + fun schemaFile(): ProtobufFile? { + return file()?.schemaFile() + } + + fun file(): ProtoTextFile? { + return when (val file = containingFile.originalFile) { + is ProtoTextFile -> file + else -> null + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementBase.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementBase.kt new file mode 100644 index 00000000..8f6c798d --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementBase.kt @@ -0,0 +1,32 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.extapi.psi.ASTWrapperPsiElement +import com.intellij.lang.ASTNode +import com.intellij.navigation.ItemPresentation +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiNameIdentifierOwner + +abstract class ProtoTextElementBase(node: ASTNode) : ASTWrapperPsiElement(node) { + override fun getPresentation(): ItemPresentation? { + if (this is ItemPresentation) return this + return null + } + + override fun getTextOffset(): Int { + if (this is PsiNameIdentifierOwner) { + if (this.nameIdentifier == this) { + return super.getTextOffset() + } + return this.nameIdentifier?.textOffset ?: super.getTextOffset() + } + return super.getTextOffset() + } + + override fun getNavigationElement(): PsiElement { + return if (this is PsiNameIdentifierOwner) { + this.nameIdentifier ?: this + } else { + this + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementType.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementType.kt new file mode 100644 index 00000000..10dc41d2 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextElementType.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +open class ProtoTextElementType(name: String) : IElementType(name, ProtoTextLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextEnumValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextEnumValue.kt new file mode 100644 index 00000000..1c4bdbb1 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextEnumValue.kt @@ -0,0 +1,31 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.key +import io.kanro.idea.plugin.protobuf.lang.psi.proto.value + +fun ProtoTextEnumValue.enum(): ProtobufEnumDefinition? { + val assign = parentOfType() ?: return null + val field = assign.field() ?: return null + + return when (field) { + is ProtobufFieldDefinition -> { + field.typeName.resolve() as? ProtobufEnumDefinition + } + + is ProtobufMapFieldDefinition -> { + val targetField = assign.field()?.text ?: return null + when (targetField) { + "key" -> field.key()?.resolve() as? ProtobufEnumDefinition + "value" -> field.value()?.resolve() as? ProtobufEnumDefinition + else -> null + } + } + + else -> null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFieldName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFieldName.kt new file mode 100644 index 00000000..65de2965 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFieldName.kt @@ -0,0 +1,39 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.psi.util.parentOfType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue + +fun ProtoTextFieldName.resolve(): ProtobufElement? { + symbolName?.let { + return reference?.resolve() as? ProtobufElement + } + + extensionName?.let { + return it.typeName.leaf().reference?.resolve() as? ProtobufElement + } + + anyName?.let { + return it.typeName.leaf().reference?.resolve() as? ProtobufElement + } + + return null +} + +fun ProtoTextFieldName.ownerMessage(): ProtobufScope? { + val field = parent as? ProtoTextField ?: return null + val message = field.parent as? MessageValue ?: return null + + if (message is ProtoTextFile) { + return message.schema() + } + + val parentField = message.parentOfType()?.fieldName?.resolve() ?: return null + + if (parentField is ProtobufScope) return parentField + if (parentField is ProtobufFieldDefinition) return parentField.typeName.resolve() as? ProtobufScope + + return null +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFile.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFile.kt new file mode 100644 index 00000000..5dcf4e1b --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextFile.kt @@ -0,0 +1,48 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.intellij.navigation.ItemPresentation +import com.intellij.psi.PsiFile +import com.intellij.psi.tree.IFileElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextHeaderFileReference +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextHeaderMessageReference +import io.kanro.idea.plugin.protobuf.lang.psi.value.MessageValue + +interface ProtoTextFile : + PsiFile, + NamedElement, + ItemPresentation, + MessageValue { + fun schemaFile(): ProtobufFile? { + children.forEach { + if (it is ProtoTextSharpLineCommentImpl) { + when (val reference = it.reference) { + is ProtoTextHeaderFileReference -> return reference.resolve() as? ProtobufFile + } + } + } + return null + } + + fun schema(): ProtobufMessageDefinition? { + children.forEach { + if (it is ProtoTextSharpLineCommentImpl) { + when (val reference = it.reference) { + is ProtoTextHeaderMessageReference -> return reference.resolve() as? ProtobufMessageDefinition + } + } + } + return null + } + + object Type : IFileElementType("PROTOTEXT_FILE", ProtoTextLanguage) + + companion object { + const val PROTOTEXT_HEADER_FILE = "# proto-file:" + const val PROTOTEXT_HEADER_MESSAGE = "# proto-message:" + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextPsiFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextPsiFactory.kt new file mode 100644 index 00000000..8c88c5b1 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextPsiFactory.kt @@ -0,0 +1,50 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +import com.bybutter.sisyphus.string.escape +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFileFactory +import io.kanro.idea.plugin.protobuf.lang.ProtoTextFileType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufStringValue +import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren + +object ProtoTextPsiFactory { + fun createFile( + project: Project, + text: String, + ): ProtoTextFile { + val name = "dummy.txtpb" + return PsiFileFactory.getInstance(project) + .createFileFromText(name, ProtoTextFileType.INSTANCE, text) as ProtoTextFile + } + + fun createFieldName( + project: Project, + text: String, + ): ProtoTextFieldName { + ProtobufPsiFactory.createFile(project, "$text = 1;").walkChildren { + return it.fieldName + } + throw IllegalStateException("Wrong type name '$text'") + } + + fun createTypeName( + project: Project, + text: String, + ): ProtoTextTypeName { + ProtobufPsiFactory.createFile(project, "[$text] = 1;").walkChildren { + return it + } + throw IllegalStateException("Wrong type name '$text'") + } + + fun createStringValue( + project: Project, + text: String, + ): ProtobufStringValue { + ProtobufPsiFactory.createFile(project, "a = \"${text.escape()}\";").walkChildren { + return it + } + throw IllegalStateException("Wrong string value '$text'") + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextTypeName.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextTypeName.kt new file mode 100644 index 00000000..ea0c897e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/ProtoTextTypeName.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text + +fun ProtoTextTypeName.scope(): ProtoTextElement { + return root().parent as ProtoTextElement +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/feature/ProtoTextFieldAssign.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/feature/ProtoTextFieldAssign.kt new file mode 100644 index 00000000..fcd96e58 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/feature/ProtoTextFieldAssign.kt @@ -0,0 +1,19 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.feature + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.findChild +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.resolve + +interface ProtoTextFieldAssign : ValueAssign { + override fun field(): ProtobufFieldLike? { + val field = findChild() ?: return null + return field.resolve() as? ProtobufFieldLike + } + + override fun valueElement(): ValueElement<*>? { + return findChild>() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextFileImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextFileImpl.kt new file mode 100644 index 00000000..3cc644f4 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextFileImpl.kt @@ -0,0 +1,43 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.impl + +import com.intellij.extapi.psi.PsiFileBase +import com.intellij.navigation.ItemPresentation +import com.intellij.openapi.fileTypes.FileType +import com.intellij.psi.FileViewProvider +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.ProtoTextFileType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import javax.swing.Icon + +class ProtoTextFileImpl(viewProvider: FileViewProvider) : + PsiFileBase(viewProvider, ProtoTextLanguage), + ProtoTextFile { + override fun getFileType(): FileType { + return ProtoTextFileType.INSTANCE + } + + override fun toString(): String { + return "Protobuf File Text Format" + } + + override fun getPresentableText(): String? { + return name() + } + + override fun name(): String { + return this.name + } + + override fun getPresentation(): ItemPresentation? { + return this + } + + override fun getLocationString(): String? { + return null + } + + override fun getIcon(unused: Boolean): Icon? { + return ProtobufIcons.TEXT_FILE + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextSharpLineCommentImpl.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextSharpLineCommentImpl.kt new file mode 100644 index 00000000..a155bfe5 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/impl/ProtoTextSharpLineCommentImpl.kt @@ -0,0 +1,22 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.impl + +import com.intellij.psi.PsiReference +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry +import com.intellij.psi.impl.source.tree.PsiCommentImpl +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElement + +class ProtoTextSharpLineCommentImpl(type: IElementType, text: CharSequence) : + PsiCommentImpl(type, text), ProtoTextElement { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return ReferenceProvidersRegistry.getReferencesFromProviders(this) + } + + override fun toString(): String { + return "ProtoTextSharpLineComment($elementType)" + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextEnumValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextEnumValueMixin.kt new file mode 100644 index 00000000..35202b88 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextEnumValueMixin.kt @@ -0,0 +1,13 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextEnumValueReference + +abstract class ProtoTextEnumValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtoTextEnumValue { + override fun getReference(): PsiReference { + return ProtoTextEnumValueReference(this) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextFieldNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextFieldNameMixin.kt new file mode 100644 index 00000000..becec474 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextFieldNameMixin.kt @@ -0,0 +1,31 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextFieldReference + +abstract class ProtoTextFieldNameMixin(node: ASTNode) : + ProtoTextElementBase(node), + ProtoTextFieldName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return CachedValuesManager.getCachedValue(this) { + CachedValueProvider.Result( + if (symbolName != null) { + arrayOf(ProtoTextFieldReference(this)) + } else { + emptyArray() + }, + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextStringValueMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextStringValueMixin.kt new file mode 100644 index 00000000..5b317374 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextStringValueMixin.kt @@ -0,0 +1,28 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextStringValue + +abstract class ProtoTextStringValueMixin(node: ASTNode) : ProtobufElementBase(node), ProtoTextStringValue { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return ReferenceProvidersRegistry.getReferencesFromProviders(this) + } + + override fun symbol(): QualifiedName? { + return (reference?.resolve() as? ProtobufScope)?.scope() + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtoTextPsiFactory.createStringValue(project, qualifiedName.toString())) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextTypeNameMixin.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextTypeNameMixin.kt new file mode 100644 index 00000000..42262ba3 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/mixin/ProtoTextTypeNameMixin.kt @@ -0,0 +1,57 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.mixin + +import com.intellij.lang.ASTNode +import com.intellij.psi.PsiReference +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import com.intellij.psi.util.QualifiedName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextElementBase +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.text.reference.ProtoTextTypeNameReference + +abstract class ProtoTextTypeNameMixin(node: ASTNode) : ProtoTextElementBase(node), ProtoTextTypeName { + override fun getReference(): PsiReference? { + return references.firstOrNull() + } + + override fun getReferences(): Array { + return CachedValuesManager.getCachedValue(this) { + CachedValueProvider.Result( + arrayOf(ProtoTextTypeNameReference(this)), + PsiModificationTracker.MODIFICATION_COUNT, + ) + } + } + + override fun symbol(): QualifiedName? { + return buildList { + var parent = this@ProtoTextTypeNameMixin as? ProtoTextTypeName + while (parent != null) { + add(parent.symbolName.text) + parent = parent.parent as? ProtoTextTypeName + } + }.reversed().let { QualifiedName.fromComponents(it) } + } + + override fun rename(qualifiedName: QualifiedName) { + replace(ProtoTextPsiFactory.createTypeName(project, qualifiedName.toString())) + } + + override fun leaf(): ProtoTextTypeName { + var result: ProtoTextTypeName = this + while (true) { + result = result.typeName ?: break + } + return result + } + + override fun root(): ProtoTextTypeName { + var result: ProtoTextTypeName = this + while (true) { + result = result.parent as? ProtoTextTypeName ?: break + } + return result + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextEnumValueReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextEnumValueReference.kt new file mode 100644 index 00000000..93d409d1 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextEnumValueReference.kt @@ -0,0 +1,41 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.tree.LeafElement +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.realItems +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextEnumValue +import io.kanro.idea.plugin.protobuf.lang.psi.text.enum + +class ProtoTextEnumValueReference(field: ProtoTextEnumValue) : + PsiReferenceBase(field) { + override fun resolve(): PsiElement? { + element.enum()?.items { + if (it.name() == element.text) { + return it + } + } + return null + } + + override fun calculateDefaultRangeInElement(): TextRange { + return TextRange.create(0, element.textLength) + } + + override fun getVariants(): Array { + return element.enum()?.realItems()?.mapNotNull { + if (it !is ProtobufEnumValueDefinition) return@mapNotNull null + (it as? LookupableElement)?.lookup() + }?.toTypedArray() ?: ArrayUtilRt.EMPTY_OBJECT_ARRAY + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.identifierLiteral?.node as? LeafElement)?.replaceWithText(newElementName) + return element + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextFieldReference.kt new file mode 100644 index 00000000..f64dabf8 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextFieldReference.kt @@ -0,0 +1,92 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.items +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.key +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.value +import io.kanro.idea.plugin.protobuf.lang.psi.realItems +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextPsiFactory +import io.kanro.idea.plugin.protobuf.lang.psi.text.ownerMessage + +class ProtoTextFieldReference(field: ProtoTextFieldName) : + PsiReferenceBase(field) { + override fun resolve(): PsiElement? { + val message = element.ownerMessage() ?: return null + if (message is ProtobufMapFieldDefinition) { + when (element.text) { + "key" -> return message.key() + "value" -> return message.value() + } + } + message.items { + if (it.fieldName() == element.text) { + return it + } + } + return null + } + + override fun calculateDefaultRangeInElement(): TextRange { + return TextRange.create(0, element.textLength) + } + + override fun getVariants(): Array { + val message = element.ownerMessage() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + return when (message) { + is ProtobufMapFieldDefinition -> { + message.entryFields().map { + when (it.psiElement?.reference?.resolve()) { + is ProtobufGroupDefinition, + is ProtobufMessageDefinition, + -> it.withInsertHandler(messageFieldInsertHandler) + + else -> it.withInsertHandler(fieldInsertHandler) + } + }.toTypedArray() + } + + else -> { + message.realItems().mapNotNull { + when (it) { + is ProtobufFieldDefinition -> + when (it.typeName.resolve()) { + is ProtobufMessageDefinition -> { + it.lookup()?.withInsertHandler(messageFieldInsertHandler) + } + + else -> it.lookup()?.withInsertHandler(fieldInsertHandler) + } + + is ProtobufMapFieldDefinition -> it.lookup()?.withInsertHandler(messageFieldInsertHandler) + + is ProtobufGroupDefinition -> it.lookup()?.withInsertHandler(messageFieldInsertHandler) + + else -> null + } + }.toTypedArray() + } + } + } + + override fun handleElementRename(newElementName: String): PsiElement { + ProtoTextPsiFactory.createFieldName(element.project, newElementName).let { + return element.replace(it) + } + } + + companion object { + private val fieldInsertHandler = SmartInsertHandler(": ") + + private val messageFieldInsertHandler = SmartInsertHandler(" {}", -1) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderFileReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderFileReference.kt new file mode 100644 index 00000000..e2a9d28a --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderFileReference.kt @@ -0,0 +1,91 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.codeInsight.lookup.AutoCompletionPolicy +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiManager +import com.intellij.psi.PsiReferenceBase +import io.kanro.idea.plugin.protobuf.ProtobufIcons +import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver + +class ProtoTextHeaderFileReference(comment: ProtoTextSharpLineCommentImpl) : + PsiReferenceBase(comment) { + override fun resolve(): PsiElement? { + val fileName = fileName() + return if (fileName.startsWith(".")) { + element.containingFile.originalFile.virtualFile.parent?.findFileByRelativePath(fileName)?.let { + PsiManager.getInstance(element.project).findFile(it) + } + } else { + ProtobufRootResolver.findFile(fileName, element).firstOrNull()?.let { + PsiManager.getInstance(element.project).findFile(it) + } + } + } + + override fun getRangeInElement(): TextRange { + val text = element.text + val fileName = fileName() + val start = text.indexOf(fileName) + return TextRange.create(start, start + fileName.length) + } + + fun fileName(): String { + return element.text.substringAfter(ProtoTextFile.PROTOTEXT_HEADER_FILE).trim() + } + + override fun getVariants(): Array { + val imported = fileName() + val parent = imported.substringBeforeLast('/', "") + return if (parent.startsWith(".")) { + element.containingFile.originalFile.virtualFile?.parent?.findFileByRelativePath(parent) + ?.children?.mapNotNull { + fileLookup(parent, it) + }?.toTypedArray() ?: emptyArray() + } else { + ProtobufRootResolver.collectProtobuf(parent, element).mapNotNull { + fileLookup(parent, it) + }.toTypedArray() + } + } + + companion object { + private val nextImportInsert = SmartInsertHandler("/", 0, true) + + private fun fileLookup( + parent: String, + file: VirtualFile, + ): LookupElement? { + val completionText = + if (parent == "") { + file.name + } else { + "$parent/${file.name}".trim('/') + } + + return if (file.isDirectory) { + LookupElementBuilder.create(completionText) + .withTypeText("directory") + .withIcon(ProtobufIcons.FOLDER) + .withPresentableText(file.name) + .withInsertHandler { context, item -> + nextImportInsert.handleInsert(context, item) + } + .withAutoCompletionPolicy(AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE) + } else { + if (file.fileType !is ProtobufFileType) return null + LookupElementBuilder.create(completionText) + .withTypeText("proto") + .withIcon(ProtobufIcons.FILE) + .withPresentableText(file.name) + } + } + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderMessageReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderMessageReference.kt new file mode 100644 index 00000000..b0bf3420 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextHeaderMessageReference.kt @@ -0,0 +1,60 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.util.QualifiedName +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver + +class ProtoTextHeaderMessageReference(comment: ProtoTextSharpLineCommentImpl) : + PsiReferenceBase(comment) { + override fun resolve(): PsiElement? { + val messageName = messageName() + return ProtobufSymbolResolver.resolveInScope( + element.schemaFile() ?: return null, + QualifiedName.fromDottedString(messageName), + ) as? ProtobufMessageDefinition + } + + override fun getRangeInElement(): TextRange { + val text = element.text + val messageName = messageName() + val start = text.indexOf(messageName) + return TextRange.create(start, start + messageName.length) + } + + override fun getVariants(): Array { + val result = mutableListOf() + val filter = ProtobufSymbolFilters.messageTypeName + val messageName = messageName() + val parentScope = + messageName.substringBeforeLast('.', "").takeIf { it.isNotEmpty() } + ?.let { QualifiedName.fromDottedString(it) } ?: QualifiedName.fromComponents() + val scopeElement = element.schemaFile() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY + ProtobufSymbolResolver.collectInScope(scopeElement, parentScope, filter).forEach { + result += lookupFor(it, parentScope) ?: return@forEach + } + return result.toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + val lookupElement = element as? LookupableElement ?: return null + val fullName = scope.append(lookupElement.name).toString() + return lookupElement.lookup(fullName) + } + + fun messageName(): String { + return element.text.substringAfter(ProtoTextFile.PROTOTEXT_HEADER_MESSAGE).trim() + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextSharpCommentReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextSharpCommentReferenceContributor.kt new file mode 100644 index 00000000..c74abfea --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextSharpCommentReferenceContributor.kt @@ -0,0 +1,43 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceContributor +import com.intellij.psi.PsiReferenceProvider +import com.intellij.psi.PsiReferenceRegistrar +import com.intellij.util.ProcessingContext +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFile +import io.kanro.idea.plugin.protobuf.lang.psi.text.impl.ProtoTextSharpLineCommentImpl + +class ProtoTextSharpCommentReferenceContributor : PsiReferenceContributor() { + override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { + registrar.registerReferenceProvider( + PlatformPatterns.psiElement(ProtoTextSharpLineCommentImpl::class.java) + .withParent(ProtoTextFile::class.java), + ProtoTextSharpCommentReferenceProvider(), + ) + } +} + +class ProtoTextSharpCommentReferenceProvider : PsiReferenceProvider() { + override fun getReferencesByElement( + element: PsiElement, + context: ProcessingContext, + ): Array { + val stringValue = element as? ProtoTextSharpLineCommentImpl ?: return PsiReference.EMPTY_ARRAY + val reference = getReference(stringValue) ?: return PsiReference.EMPTY_ARRAY + return arrayOf(reference) + } + + private fun getReference(element: ProtoTextSharpLineCommentImpl): PsiReference? { + val text = element.text + if (text.startsWith(ProtoTextFile.PROTOTEXT_HEADER_FILE)) { + return ProtoTextHeaderFileReference(element) + } + if (text.startsWith(ProtoTextFile.PROTOTEXT_HEADER_MESSAGE)) { + return ProtoTextHeaderMessageReference(element) + } + return null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextTypeNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextTypeNameReference.kt new file mode 100644 index 00000000..9dd4d2cb --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/reference/ProtoTextTypeNameReference.kt @@ -0,0 +1,193 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.reference + +import com.intellij.codeInsight.completion.CompletionUtilCore +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.patterns.PlatformPatterns +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiReference +import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.impl.source.resolve.ResolveCache +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.stubs.StubIndex +import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.parentOfType +import com.intellij.util.ArrayUtilRt +import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler +import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler +import io.kanro.idea.plugin.protobuf.lang.psi.feature.LookupableElement +import io.kanro.idea.plugin.protobuf.lang.psi.prev +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItem +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextAnyName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextExtensionName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.text.scope +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolFilters +import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver +import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver +import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix + +class ProtoTextTypeNameReference(typeName: ProtoTextTypeName) : PsiReferenceBase(typeName) { + private object Resolver : ResolveCache.Resolver { + override fun resolve( + ref: PsiReference, + incompleteCode: Boolean, + ): PsiElement? { + ref as ProtoTextTypeNameReference + val qualifiedName = ref.element.leaf().symbol() ?: return null + + return when (ref.element.scope()) { + is ProtoTextAnyName -> { + StubIndex.getElements( + QualifiedNameIndex.key, + qualifiedName.toString(), + ref.element.project, + GlobalSearchScope.allScope(ref.element.project), + ProtobufElement::class.java, + ).firstOrNull { it is ProtobufMessageDefinition } as? ProtobufMessageDefinition + } + + is ProtoTextExtensionName -> { + val scope = ref.element.schemaFile() ?: return null + ProtobufSymbolResolver.resolveAbsolutely(scope, qualifiedName, ProtobufSymbolFilters.extensionField) + } + + else -> null + } + } + } + + override fun resolve(): PsiElement? { + element.typeName?.let { + return when (val item = it.reference?.resolve()) { + is ProtobufScopeItem -> { + when (val owner = item.owner()) { + is ProtobufFile -> owner.packageParts().lastOrNull() + else -> owner + } + } + is ProtobufPackageName -> item.prev() + else -> null + } + } + + return ResolveCache.getInstance(element.project).resolveWithCaching(this, Resolver, false, false) + } + + override fun getCanonicalText(): String { + return element.text + } + + override fun calculateDefaultRangeInElement(): TextRange { + return element.symbolName.textRangeInParent + } + + override fun handleElementRename(newElementName: String): PsiElement { + (element.symbolName.identifierLiteral as? LeafPsiElement)?.replaceWithText(newElementName) + return element + } + + override fun getVariants(): Array { + val result = mutableListOf() + val addedElements = mutableSetOf() + val filter = + when (val scope = element.scope()) { + is ProtoTextAnyName -> ProtobufSymbolFilters.messageTypeName + is ProtoTextExtensionName -> ProtobufSymbolFilters.extensionFieldQualifiedName + else -> return ArrayUtilRt.EMPTY_OBJECT_ARRAY + } + + getVariantsInCurrentScope(filter, result, addedElements) + getVariantsInStubIndex(filter, result, addedElements) + return result.toTypedArray() + } + + private fun getVariantsInCurrentScope( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ) { + val parentScope = element.symbol() ?: return + val scopeElement = element.schemaFile() ?: return + ProtobufSymbolResolver.collectAbsolute(scopeElement, parentScope, filter).forEach { + if (it in elements) return@forEach + result += lookupFor(it, parentScope) ?: return@forEach + elements += it + } + } + + private fun getVariantsInStubIndex( + filter: PsiElementFilter, + result: MutableList, + elements: MutableSet, + ): Array { + if (element.parent is ProtoTextTypeName) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (element.typeName != null) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + if (!element.text.endsWith(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED)) return ArrayUtilRt.EMPTY_OBJECT_ARRAY + + val searchName = element.text.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) + val scope = ProtobufRootResolver.searchScope(element) + val matcher = PlatformPatterns.string().contains(searchName) + val currentScope = element.parentOfType()?.scope() + + return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { + matcher.accepts(it) + }.flatMap { + StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) + .asSequence() + }.filter { + filter.isAccepted(it) + }.mapNotNull { + if (it in elements) return@mapNotNull null + result += lookupForStub(it, currentScope) ?: return@mapNotNull null + elements += it + }.toList().toTypedArray() + } + + private fun lookupFor( + element: ProtobufElement, + scope: QualifiedName, + ): LookupElement? { + var builder = + (element as? LookupableElement)?.lookup() ?: return null + builder = builder.withLookupString(scope.append(builder.lookupString).toString()) + if (element is ProtobufPackageName) { + builder = builder.withInsertHandler(packageInsertHandler) + } + return builder + } + + private fun lookupForStub( + element: ProtobufElement, + currentScope: QualifiedName?, + ): LookupElement? { + if (element !is ProtobufDefinition) return null + val qualifiedName = element.qualifiedName() ?: return null + + val targetName = + if (currentScope != null) { + qualifiedName.removeCommonPrefix(currentScope) + } else { + qualifiedName + } + return LookupElementBuilder.create(targetName).withLookupString(qualifiedName.lastComponent!!) + .withPresentableText(qualifiedName.lastComponent!!).withIcon(element.getIcon(false)) + .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) + .withTypeText(element.type()).withInsertHandler(AddImportInsertHandler(element)) + } + + companion object { + private val packageInsertHandler = SmartInsertHandler(".", 0, true) + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextCommentToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextCommentToken.kt new file mode 100644 index 00000000..74fe9187 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextCommentToken.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.token + +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +open class ProtoTextCommentToken(name: String) : IElementType(name, ProtoTextLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextKeywordToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextKeywordToken.kt new file mode 100644 index 00000000..4c342c3b --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextKeywordToken.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.token + +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +open class ProtoTextKeywordToken(name: String) : IElementType(name, ProtoTextLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextToken.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextToken.kt new file mode 100644 index 00000000..ccac1ea8 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtoTextToken.kt @@ -0,0 +1,6 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.token + +import com.intellij.psi.tree.IElementType +import io.kanro.idea.plugin.protobuf.lang.ProtoTextLanguage + +open class ProtoTextToken(name: String) : IElementType(name, ProtoTextLanguage) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtobufTokens.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtobufTokens.kt new file mode 100644 index 00000000..04b12e42 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/text/token/ProtobufTokens.kt @@ -0,0 +1,102 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.text.token + +import com.intellij.psi.tree.IElementType + +object ProtoTextTokens { + private val types: MutableMap = mutableMapOf() + + private fun put(element: IElementType): IElementType { + return put(element.toString(), element) + } + + private fun put( + name: String, + element: IElementType, + ): IElementType { + return types.getOrPut(name) { + element + } + } + + fun get(token: String): IElementType { + return types[token] ?: throw AssertionError("Unknown token type: $token") + } + + @JvmField + val ASSIGN = put(ProtoTextToken("=")) + + @JvmField + val COLON = put(ProtoTextToken(":")) + + @JvmField + val COMMA = put(ProtoTextToken(",")) + + @JvmField + val DOT = put(ProtoTextToken(".")) + + @JvmField + val GT = put(ProtoTextToken(">")) + + @JvmField + val LBRACE = put(ProtoTextToken("{")) + + @JvmField + val LBRACK = put(ProtoTextToken("[")) + + @JvmField + val LPAREN = put(ProtoTextToken("(")) + + @JvmField + val LT = put(ProtoTextToken("<")) + + @JvmField + val MINUS = put(ProtoTextToken("-")) + + @JvmField + val PLUS = put(ProtoTextToken("+")) + + @JvmField + val RBRACE = put(ProtoTextToken("}")) + + @JvmField + val RBRACK = put(ProtoTextToken("]")) + + @JvmField + val RPAREN = put(ProtoTextToken(")")) + + @JvmField + val SEMI = put(ProtoTextToken(";")) + + @JvmField + val SLASH = put(ProtoTextToken("/")) + + @JvmField + val FLOAT_LITERAL = put("FLOAT_LITERAL", ProtoTextToken("float")) + + @JvmField + val IDENTIFIER_LITERAL = put("IDENTIFIER_LITERAL", ProtoTextToken("identifier")) + + @JvmField + val INTEGER_LITERAL = put("INTEGER_LITERAL", ProtoTextToken("integer")) + + @JvmField + val STRING_LITERAL = put("STRING_LITERAL", ProtoTextToken("string")) + + @JvmField + val BUILT_IN_TYPE = put("BUILT_IN_TYPE", ProtoTextToken("BUILT_IN_TYPE")) + + @JvmField + val IDENTIFIER_AFTER_NUMBER = put(ProtoTextToken("IDENTIFIER_AFTER_NUMBER")) + + @JvmField + val SHARP_LINE_COMMENT = put(ProtoTextCommentToken("SHARP_LINE_COMMENT")) + + @JvmField + val SYMBOL = put(ProtoTextToken("SYMBOL")) + + @JvmField + val FALSE = put(ProtoTextKeywordToken("false")) + + @JvmField + val TRUE = put(ProtoTextKeywordToken("true")) +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/BlockElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/BlockElement.kt new file mode 100644 index 00000000..adac98c1 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/BlockElement.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.type + +import com.intellij.psi.PsiElement + +interface BlockElement : PsiElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/FragmentElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/FragmentElement.kt new file mode 100644 index 00000000..e7caacef --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/FragmentElement.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.type + +import com.intellij.psi.PsiElement + +interface FragmentElement : PsiElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/StatementElement.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/StatementElement.kt new file mode 100644 index 00000000..e262958e --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/type/StatementElement.kt @@ -0,0 +1,5 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.type + +import com.intellij.psi.PsiElement + +interface StatementElement : PsiElement diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ArrayValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ArrayValue.kt new file mode 100644 index 00000000..410096ae --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ArrayValue.kt @@ -0,0 +1,19 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import com.intellij.psi.util.childrenOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface ArrayValue : ValueElement> { + override fun value(): Array = this.childrenOfType>().map { + it.value() + }.toTypedArray() + + fun value(index: Int): Any? = valueElement(index)?.value() + + fun values(): Array> = this.childrenOfType>().toTypedArray() + + fun valueElement(index: Int): ValueElement<*>? = this.childrenOfType>().getOrNull(index) + + override fun valueType(): ValueType = ValueType.LIST +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/BooleanValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/BooleanValue.kt new file mode 100644 index 00000000..21c52784 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/BooleanValue.kt @@ -0,0 +1,10 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface BooleanValue : ValueElement { + override fun value(): Boolean = this.text.toBoolean() + + override fun valueType(): ValueType = ValueType.BOOLEAN +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/EnumValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/EnumValue.kt new file mode 100644 index 00000000..f35bbf93 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/EnumValue.kt @@ -0,0 +1,10 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface EnumValue : ValueElement { + override fun value(): String = this.text + + override fun valueType(): ValueType = ValueType.ENUM +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/IntegerValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/IntegerValue.kt new file mode 100644 index 00000000..c9c40733 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/IntegerValue.kt @@ -0,0 +1,10 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface IntegerValue : ValueElement { + override fun value(): Int = this.text.toInt() + + override fun valueType(): ValueType = ValueType.NUMBER +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/MessageValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/MessageValue.kt new file mode 100644 index 00000000..93170ea7 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/MessageValue.kt @@ -0,0 +1,38 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import com.intellij.psi.util.QualifiedName +import com.intellij.psi.util.childrenOfType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueAssign +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface MessageValue : ValueElement { + override fun value(): Any = this + + override fun valueType(): ValueType = ValueType.MESSAGE + + fun value(field: QualifiedName): Any? { + return valueElement(field)?.value() + } + + fun valueElement(field: QualifiedName): ValueElement<*>? { + if (field.componentCount == 0) return this + + val fields = childrenOfType() + fields.forEach { + if (it.field()?.name() != field.firstComponent) { + return null + } + val next = field.removeHead(1) + + if (next.componentCount == 0) { + return it + } + + if (it is MessageValue) { + return it.valueElement(next) + } + } + return null + } +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/NumberValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/NumberValue.kt new file mode 100644 index 00000000..ba69fe5a --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/NumberValue.kt @@ -0,0 +1,22 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType + +interface NumberValue : ValueElement { + override fun value(): Number { + val text = this.text.lowercase() + return when { + text == "inf" -> Double.POSITIVE_INFINITY + text == "-inf" -> Double.NEGATIVE_INFINITY + text == "nan" -> Double.NaN + text.contains('e', true) -> this.text.toDouble() + text.startsWith("0x") -> this.text.substring(2).toLong(16) + text.startsWith("0") -> this.text.toLong(8) + this.text.contains('.') -> this.text.toDouble() + else -> this.text.toLong() + } + } + + override fun valueType(): ValueType = ValueType.NUMBER +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/StringValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/StringValue.kt new file mode 100644 index 00000000..f5e32a26 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/StringValue.kt @@ -0,0 +1,21 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import com.intellij.psi.util.elementType +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens + +interface StringValue : ValueElement { + override fun value(): String = + buildString { + var child = firstChild + while (child != null) { + if (child.elementType == ProtobufTokens.STRING_LITERAL) { + append(decodeStringFromStringLiteral(child)) + } + child = child.nextSibling + } + } + + override fun valueType(): ValueType = ValueType.STRING +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ValueUtils.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ValueUtils.kt new file mode 100644 index 00000000..ac59ee46 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/ValueUtils.kt @@ -0,0 +1,61 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import com.intellij.psi.PsiElement +import com.intellij.psi.util.elementType +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens + +fun decodeStringFromStringLiteral(textElement: PsiElement): String { + if (textElement.elementType != ProtobufTokens.STRING_LITERAL) { + throw IllegalArgumentException("Element is not a string literal") + } + + return decodeString(textElement.text.trim('"', '\'')) +} + +fun decodeString(text: String): String = + buildString { + var index = 0 + while (index < text.length) { + val char = text[index] + if (char == '\\') { + index++ + if (index >= text.length) { + break + } + val next = text[index] + when (next) { + 'a' -> append('\u0007') + 'b' -> append('\b') + 'f' -> append('\u000C') + 'n' -> append('\n') + 'r' -> append('\r') + 't' -> append('\t') + 'v' -> append('\u000B') + 'x' -> { + index++ + if (index >= text.length) { + break + } + val hex = text.substring(index, index + 2) + index += 2 + append(hex.toInt(16).toChar()) + } + + 'u' -> { + index++ + if (index >= text.length) { + break + } + val hex = text.substring(index, index + 4) + index += 4 + append(hex.toInt(16).toChar()) + } + + else -> append(next) + } + } else { + append(char) + } + index++ + } + } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/WrappedValue.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/WrappedValue.kt new file mode 100644 index 00000000..86be0988 --- /dev/null +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/psi/value/WrappedValue.kt @@ -0,0 +1,15 @@ +package io.kanro.idea.plugin.protobuf.lang.psi.value + +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ValueType +import io.kanro.idea.plugin.protobuf.lang.psi.findChild + +interface WrappedValue : ValueElement { + override fun value(): Any? = valueElement()?.value() + + fun valueElement(): ValueElement<*>? { + return this.findChild>() + } + + override fun valueType(): ValueType = valueElement()?.valueType() ?: ValueType.UNKNOWN +} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/AddImportFix.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/AddImportFix.kt index 6531d88b..97cdc392 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/AddImportFix.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/AddImportFix.kt @@ -8,21 +8,18 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import com.intellij.psi.stubs.StubIndex -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ShortNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ReferenceElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.ShortNameIndex import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver import io.kanro.idea.plugin.protobuf.lang.util.matchesSuffix class AddImportFix( - private val host: ProtobufSymbolReferenceHost, -) : BaseIntentionAction(), - HintAction, - HighPriorityAction { + private val host: ReferenceElement, +) : BaseIntentionAction(), HintAction, HighPriorityAction { private lateinit var elements: Array - private lateinit var hover: ProtobufSymbolReferenceHover override fun getFamilyName(): String { return "Import" @@ -34,25 +31,24 @@ class AddImportFix( file: PsiFile, ): Boolean { if (!host.isValid) return false - hover = host.referencesHover() ?: return false - val parts = hover.symbolParts() - val name = hover.symbol() - if (hover.absolutely() || parts.size > 1) { + if (host.containingFile.originalFile !is ProtobufFile) return false + val symbol = host.symbol() ?: return false + if (symbol.componentCount > 1) { this.elements = StubIndex.getElements( ShortNameIndex.key, - name.lastComponent!!, + symbol.lastComponent!!, project, ProtobufRootResolver.searchScope(host), ProtobufElement::class.java, ).filterIsInstance().filter { - it.qualifiedName()?.matchesSuffix(name) == true + it.qualifiedName()?.matchesSuffix(symbol) == true }.toTypedArray() } else { this.elements = StubIndex.getElements( ShortNameIndex.key, - name.lastComponent!!, + symbol.lastComponent!!, project, ProtobufRootResolver.searchScope(host), ProtobufElement::class.java, @@ -68,29 +64,28 @@ class AddImportFix( file: PsiFile?, ) { CommandProcessor.getInstance().runUndoTransparentAction { - createAction(project, editor, host, hover, elements).execute() + createAction(project, editor, elements).execute() } } private fun createAction( project: Project, editor: Editor, - host: ProtobufSymbolReferenceHost, - hover: ProtobufSymbolReferenceHover, elements: Array, ): ProtobufAddImportAction { - return ProtobufAddImportAction(project, editor, host, hover, elements) + return ProtobufAddImportAction(project, editor, host, elements) } override fun getText(): String { + val protobufFile = host.containingFile.originalFile as ProtobufFile return if (elements.size == 1) { - "Import from \"${elements[0].importPath(host.file())}\"" + "Import from \"${elements[0].importPath(protobufFile)}\"" } else { - "Import from \"${elements[0].importPath(host.file())}\" or other ${elements.size - 1} files" + "Import from \"${elements[0].importPath(protobufFile)}\" or other ${elements.size - 1} files" } } override fun showHint(editor: Editor): Boolean { - return createAction(editor.project ?: return false, editor, host, hover, elements).showHint() + return createAction(editor.project ?: return false, editor, elements).showHint() } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/OptimizeImportsFix.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/OptimizeImportsFix.kt index bf0f1f51..167736e5 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/OptimizeImportsFix.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/OptimizeImportsFix.kt @@ -4,8 +4,8 @@ import com.intellij.codeInsight.intention.impl.BaseIntentionAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile -import io.kanro.idea.plugin.protobuf.lang.formatter.ProtobufImportOptimizer -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.formatter.optimizeImportProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile class OptimizeImportsFix : BaseIntentionAction() { init { @@ -30,6 +30,6 @@ class OptimizeImportsFix : BaseIntentionAction() { file: PsiFile?, ) { if (file !is ProtobufFile) return - ProtobufImportOptimizer.processFile(file) + optimizeImportProtobufFile(file) } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/ProtobufAddImportAction.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/ProtobufAddImportAction.kt index 01733073..d3c24373 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/ProtobufAddImportAction.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/ProtobufAddImportAction.kt @@ -11,10 +11,12 @@ import com.intellij.openapi.ui.popup.ListPopupStep import com.intellij.openapi.ui.popup.PopupStep import com.intellij.openapi.ui.popup.util.BaseListPopupStep import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.util.parentOfType import com.intellij.ui.popup.list.ListPopupImpl -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.feature.ReferenceElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix import java.awt.BorderLayout import javax.swing.JPanel @@ -23,8 +25,7 @@ import javax.swing.ListCellRenderer class ProtobufAddImportAction( private val project: Project, private val editor: Editor, - private val host: ProtobufSymbolReferenceHost, - private val hover: ProtobufSymbolReferenceHover?, + private val host: ReferenceElement, private val elements: Array, ) : QuestionAction { private fun hintText(): String { @@ -106,24 +107,24 @@ class ProtobufAddImportAction( project, { ApplicationManager.getApplication().runWriteAction { - val file = host.file() - val targetName = name.removeCommonPrefix(file.scope()).toString() + val currentScope = host.parentOfType() ?: return@runWriteAction + val file = currentScope.file() + val targetName = name.removeCommonPrefix(currentScope.scope()) file.addImport(element) - if (hover != null) { - val parts = hover.symbolParts() - if (!hover.absolutely() && parts.size == 1) { - if (parts.first().value != targetName) { - hover.rename(targetName) - } + val symbol = host.symbol() + if (symbol != null) { + val parts = symbol.components + if (parts.size == 1) { + host.rename(targetName) } } PsiDocumentManager.getInstance(project).commitAllDocuments() } }, - "Import ${element.importPath(host.file())}", + "Import ${element.importPath(host.containingFile.originalFile as ProtobufFile)}", null, ) return true diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/RenameFix.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/RenameFix.kt index 43b5c386..d5f394af 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/RenameFix.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/quickfix/RenameFix.kt @@ -7,8 +7,8 @@ import com.intellij.openapi.project.Project import com.intellij.psi.PsiElement import com.intellij.psi.util.parentOfType import com.intellij.refactoring.RefactoringFactory -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition class RenameFix(private val newName: String) : PsiElementBaseIntentionAction() { init { @@ -33,7 +33,7 @@ class RenameFix(private val newName: String) : PsiElementBaseIntentionAction() { element: PsiElement, ) { DumbService.getInstance(project).smartInvokeLater { - val namedElement = element.parentOfType(true) ?: return@smartInvokeLater + val namedElement = element.parentOfType(true) ?: return@smartInvokeLater RefactoringFactory.getInstance(project).createRename(namedElement, newName).run() } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufBuiltInOptionReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufBuiltInOptionReference.kt deleted file mode 100644 index 015d3a61..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufBuiltInOptionReference.kt +++ /dev/null @@ -1,108 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.reference - -import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiManager -import com.intellij.psi.PsiReferenceBase -import com.intellij.psi.util.QualifiedName -import com.intellij.psi.util.parentOfType -import com.intellij.util.ArrayUtilRt -import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.isFieldDefaultOption -import io.kanro.idea.plugin.protobuf.lang.psi.isFieldJsonNameOption -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.realItems -import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver -import io.kanro.idea.plugin.protobuf.lang.support.Options - -class ProtobufBuiltInOptionReference(name: ProtobufBuiltInOptionName) : - PsiReferenceBase(name) { - private fun optionType(): String? { - val owner = element.parentOfType() ?: return null - return when (owner) { - is ProtobufFile -> Options.FILE_OPTIONS.messageName - is ProtobufMessageDefinition, is ProtobufGroupDefinition -> Options.MESSAGE_OPTIONS.messageName - is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> Options.FIELD_OPTIONS.messageName - is ProtobufOneofDefinition -> Options.ONEOF_OPTIONS.messageName - is ProtobufEnumDefinition -> Options.ENUM_OPTIONS.messageName - is ProtobufEnumValueDefinition -> Options.ENUM_VALUE_OPTIONS.messageName - is ProtobufServiceDefinition -> Options.SERVICE_OPTIONS.messageName - is ProtobufRpcDefinition -> Options.METHOD_OPTIONS.messageName - else -> null - } - } - - override fun resolve(): PsiElement? { - if (element.isFieldJsonNameOption()) { - return ProtobufSymbolResolver.resolveInScope( - descriptor() ?: return null, - QualifiedName.fromComponents("FieldDescriptorProto", "json_name"), - ) - } - if (element.isFieldDefaultOption()) { - return element.parentOfType() as? ProtobufFieldLike - } - - return ProtobufSymbolResolver.resolveInScope( - descriptor() ?: return null, - QualifiedName.fromComponents(optionType(), element.text), - ) - } - - override fun getVariants(): Array { - val type = optionType() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val descriptor = descriptor() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val message = - ProtobufSymbolResolver.resolveInScope( - descriptor, - QualifiedName.fromComponents(type), - ) as? ProtobufMessageDefinition ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val fields: MutableList = - message.realItems().mapNotNull { - if (it !is ProtobufFieldDefinition) return@mapNotNull null - (it as? ProtobufLookupItem)?.lookup()?.withInsertHandler(optionInsertHandler) - }.toMutableList() - if (Options.FIELD_OPTIONS.messageName == type) { - fields += - LookupElementBuilder.create("default") - .withTypeText("option") - .withIcon(ProtobufIcons.FIELD) - .withInsertHandler(optionInsertHandler) - fields += - LookupElementBuilder.create("json_name") - .withTypeText("option") - .withIcon(ProtobufIcons.FIELD) - .withInsertHandler(optionInsertHandler) - } - return fields.toTypedArray() - } - - override fun calculateDefaultRangeInElement(): TextRange { - return element.identifierLiteral!!.textRangeInParent - } - - private fun descriptor(): ProtobufFile? { - return ProtobufRootResolver.findFile("google/protobuf/descriptor.proto", element).firstOrNull()?.let { - PsiManager.getInstance(element.project).findFile(it) as? ProtobufFile - } - } - - companion object { - private val optionInsertHandler = SmartInsertHandler(" = ") - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufFieldReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufFieldReference.kt deleted file mode 100644 index a8fff98f..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufFieldReference.kt +++ /dev/null @@ -1,55 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.reference - -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiReferenceBase -import com.intellij.psi.impl.source.tree.LeafElement -import com.intellij.util.ArrayUtilRt -import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldAssign -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.message -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.realItems - -class ProtobufFieldReference(field: ProtobufFieldName) : - PsiReferenceBase(field) { - override fun resolve(): PsiElement? { - val message = element.message() ?: return null - message.items { - if (it.fieldName() == element.text) { - return it - } - } - return null - } - - override fun calculateDefaultRangeInElement(): TextRange { - return TextRange.create(0, element.textLength) - } - - override fun getVariants(): Array { - val message = element.message() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - return message.realItems().mapNotNull { - (it as? ProtobufFieldLike)?.lookup()?.let { - when (element.parent) { - is ProtobufFieldAssign -> it.withInsertHandler(fieldInsertHandler) - is ProtobufOptionName -> it.withInsertHandler(optionInsertHandler) - else -> it - } - } - }.toTypedArray() - } - - override fun handleElementRename(newElementName: String): PsiElement { - (element.identifierLiteral?.node as? LeafElement)?.replaceWithText(newElementName) - return element - } - - companion object { - private val fieldInsertHandler = SmartInsertHandler(": ") - private val optionInsertHandler = SmartInsertHandler(" = ") - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufGotoSymbolContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufGotoSymbolContributor.kt index 5af85c00..1d5c0eea 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufGotoSymbolContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufGotoSymbolContributor.kt @@ -5,8 +5,8 @@ import com.intellij.navigation.NavigationItem import com.intellij.openapi.project.Project import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.stubs.StubIndex -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex class ProtobufGotoSymbolContributor : ChooseByNameContributor { override fun getNames( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufRefactoringSupportProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufRefactoringSupportProvider.kt index 5284c171..773658b0 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufRefactoringSupportProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufRefactoringSupportProvider.kt @@ -2,13 +2,13 @@ package io.kanro.idea.plugin.protobuf.lang.reference import com.intellij.lang.refactoring.RefactoringSupportProvider import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufNamedElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.NamedElement class ProtobufRefactoringSupportProvider : RefactoringSupportProvider() { override fun isMemberInplaceRenameAvailable( elementToRename: PsiElement, context: PsiElement?, ): Boolean { - return elementToRename is ProtobufNamedElement + return elementToRename is NamedElement } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolFilters.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolFilters.kt index a48b3ed0..61db2a94 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolFilters.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolFilters.kt @@ -2,111 +2,69 @@ package io.kanro.idea.plugin.protobuf.lang.reference import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiElementFilter +import com.intellij.psi.util.QualifiedName import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendBody -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.stratify.ProtobufOptionOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendBody +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName import io.kanro.idea.plugin.protobuf.lang.support.Options -import io.kanro.idea.plugin.protobuf.lang.util.and import io.kanro.idea.plugin.protobuf.lang.util.or object ProtobufSymbolFilters { - val packagePart = + val packageName = PsiElementFilter { it is ProtobufPackageName } - fun extensionOptionName(owner: ProtobufOptionOwner?): PsiElementFilter { - return when (owner) { - is ProtobufFile -> fileExtensionOptionName - is ProtobufMessageDefinition, is ProtobufGroupDefinition -> messageExtensionOptionName - is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> fieldExtensionOptionName - is ProtobufOneofDefinition -> oneofExtensionOptionName - is ProtobufEnumDefinition -> enumExtensionOptionName - is ProtobufEnumValueDefinition -> enumValueExtensionOptionName - is ProtobufServiceDefinition -> serviceExtensionOptionName - is ProtobufRpcDefinition -> methodExtensionOptionName - else -> extensionOptionName + val fieldType = + PsiElementFilter { + it is ProtobufEnumDefinition || it is ProtobufMessageDefinition } - } - private val extensionOptionName = + val message = PsiElementFilter { - (it is ProtobufFieldDefinition || it is ProtobufGroupDefinition) && it.parent is ProtobufExtendBody + it is ProtobufMessageDefinition } - private val fileExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.FILE_OPTIONS) - private val messageExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.MESSAGE_OPTIONS) - private val fieldExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.FIELD_OPTIONS) - private val oneofExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.ONEOF_OPTIONS) - private val enumExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.ENUM_OPTIONS) - private val enumValueExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.ENUM_VALUE_OPTIONS) - private val serviceExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.SERVICE_OPTIONS) - private val methodExtensionOptionName = extensionOptionName and TargetOptionFilter(Options.METHOD_OPTIONS) - fun extensionOptionNameVariants(owner: ProtobufOptionOwner?): PsiElementFilter { - return when (owner) { - is ProtobufFile -> fileExtensionOptionNameVariants - is ProtobufMessageDefinition, is ProtobufGroupDefinition -> messageExtensionOptionNameVariants - is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> fieldExtensionOptionNameVariants - is ProtobufOneofDefinition -> oneofExtensionOptionNameVariants - is ProtobufEnumDefinition -> enumExtensionOptionNameVariants - is ProtobufEnumValueDefinition -> enumValueExtensionOptionNameVariants - is ProtobufServiceDefinition -> serviceExtensionOptionNameVariants - is ProtobufRpcDefinition -> methodExtensionOptionNameVariants - else -> extensionOptionNameVariants + val extendMessage = + PsiElementFilter { + it is ProtobufMessageDefinition || it is ProtobufGroupDefinition } - } - private val extensionOptionNameVariants = extensionOptionName or packagePart - private val fileExtensionOptionNameVariants = fileExtensionOptionName or packagePart - private val messageExtensionOptionNameVariants = messageExtensionOptionName or packagePart - private val fieldExtensionOptionNameVariants = fieldExtensionOptionName or packagePart - private val oneofExtensionOptionNameVariants = oneofExtensionOptionName or packagePart - private val enumExtensionOptionNameVariants = enumExtensionOptionName or packagePart - private val enumValueExtensionOptionNameVariants = enumValueExtensionOptionName or packagePart - private val serviceExtensionOptionNameVariants = serviceExtensionOptionName or packagePart - private val methodExtensionOptionNameVariants = methodExtensionOptionName or packagePart + val messageTypeName = message or packageName - val fieldTypeName = + val field = PsiElementFilter { - it is ProtobufEnumDefinition || it is ProtobufMessageDefinition + it is ProtobufFieldDefinition || it is ProtobufGroupDefinition } - val fieldTypeNameVariants = packagePart or fieldTypeName - - val rpcTypeName = + val extensionField = PsiElementFilter { - it is ProtobufMessageDefinition + (it is ProtobufFieldDefinition || it is ProtobufGroupDefinition) && it.parent is ProtobufExtendBody } - val rpcTypeNameVariants = packagePart or rpcTypeName + fun extensionField(message: QualifiedName): PsiElementFilter = MessageExtensionFilter(message) - val extendTypeName = - PsiElementFilter { - it is ProtobufMessageDefinition - } + fun extensionField(option: Options): PsiElementFilter = MessageExtensionFilter(option.qualifiedName) + + val extensionFieldQualifiedName = extensionField or packageName + + fun extensionFieldQualifiedName(message: QualifiedName) = extensionField(message) or packageName - val extendTypeNameVariants = packagePart or extendTypeName + fun extensionFieldQualifiedName(option: Options) = extensionField(option) or packageName val alwaysFalse = PsiElementFilter { false } - private class TargetOptionFilter(private val option: Options) : PsiElementFilter { + private class MessageExtensionFilter(private val message: QualifiedName) : PsiElementFilter { override fun isAccepted(element: PsiElement): Boolean { val extend = element.parentOfType() ?: return false val name = - (extend.typeName?.reference?.resolve() as? ProtobufMessageDefinition)?.qualifiedName() ?: return false - return name == option.qualifiedName + (extend.typeName?.resolve() as? ProtobufMessageDefinition)?.qualifiedName() ?: return false + return name == message } } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolReferenceContributor.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolReferenceContributor.kt index bbc73c5e..14af4ed5 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolReferenceContributor.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolReferenceContributor.kt @@ -1,55 +1,43 @@ package io.kanro.idea.plugin.protobuf.lang.reference -import com.intellij.patterns.PlatformPatterns -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiReference -import com.intellij.psi.PsiReferenceContributor -import com.intellij.psi.PsiReferenceProvider -import com.intellij.psi.PsiReferenceRegistrar -import com.intellij.psi.util.CachedValueProvider -import com.intellij.psi.util.CachedValuesManager -import com.intellij.psi.util.PsiModificationTracker -import com.intellij.util.ProcessingContext -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.support.BuiltInType - -class ProtobufSymbolReferenceContributor : PsiReferenceContributor() { - override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { - registrar.registerReferenceProvider( - PlatformPatterns.psiElement(ProtobufSymbolReferenceHost::class.java), - ProtobufSymbolReferenceProvider, - ) - } -} - -object ProtobufSymbolReferenceProvider : PsiReferenceProvider() { - override fun getReferencesByElement( - element: PsiElement, - context: ProcessingContext, - ): Array { - element as ProtobufSymbolReferenceHost - return CachedValuesManager.getCachedValue(element) { - val hover = - element.referencesHover() - ?: return@getCachedValue CachedValueProvider.Result.create( - PsiReference.EMPTY_ARRAY, - PsiModificationTracker.MODIFICATION_COUNT, - ) - val symbol = hover.symbol() - if (!hover.absolutely() && symbol.componentCount == 1 && BuiltInType.isBuiltInType(symbol.firstComponent!!)) { - return@getCachedValue CachedValueProvider.Result.create( - PsiReference.EMPTY_ARRAY, - PsiModificationTracker.MODIFICATION_COUNT, - ) - } - var reference: ProtobufTypeNameReference? = null - val result = - symbol.components.reversed().mapIndexed { index, name -> - ProtobufTypeNameReference(element, hover, symbol.componentCount - 1 - index, reference).apply { - reference = this - } - }.toTypedArray() - CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT) - } - } -} +// +// class ProtobufSymbolReferenceContributor : PsiReferenceContributor() { +// override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) { +// registrar.registerReferenceProvider( +// PlatformPatterns.psiElement(ProtobufSymbolReferenceHost::class.java), +// ProtobufSymbolReferenceProvider, +// ) +// } +// } +// +// object ProtobufSymbolReferenceProvider : PsiReferenceProvider() { +// override fun getReferencesByElement( +// element: PsiElement, +// context: ProcessingContext, +// ): Array { +// element as ProtobufSymbolReferenceHost +// return CachedValuesManager.getCachedValue(element) { +// val hover = +// element.referencesHover() +// ?: return@getCachedValue CachedValueProvider.Result.create( +// PsiReference.EMPTY_ARRAY, +// PsiModificationTracker.MODIFICATION_COUNT, +// ) +// val symbol = hover.symbol() +// if (!hover.absolutely() && symbol.componentCount == 1 && BuiltInType.isBuiltInType(symbol.firstComponent!!)) { +// return@getCachedValue CachedValueProvider.Result.create( +// PsiReference.EMPTY_ARRAY, +// PsiModificationTracker.MODIFICATION_COUNT, +// ) +// } +// var reference: ProtobufTypeNameReference? = null +// val result = +// symbol.components.reversed().mapIndexed { index, name -> +// ProtobufTypeNameReference(element, hover, symbol.componentCount - 1 - index, reference).apply { +// reference = this +// } +// }.toTypedArray() +// CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT) +// } +// } +// } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolResolver.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolResolver.kt index 5858775b..1daf0cb1 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolResolver.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufSymbolResolver.kt @@ -3,13 +3,14 @@ package io.kanro.idea.plugin.protobuf.lang.reference import com.intellij.psi.util.PsiElementFilter import com.intellij.psi.util.QualifiedName import com.intellij.psi.util.parentOfType -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile import io.kanro.idea.plugin.protobuf.lang.psi.items -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.public -import io.kanro.idea.plugin.protobuf.lang.psi.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.public +import io.kanro.idea.plugin.protobuf.lang.psi.proto.resolve +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufMultiNameDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScope import io.kanro.idea.plugin.protobuf.lang.util.AnyElement import java.util.Stack @@ -127,7 +128,13 @@ object ProtobufSymbolResolver { filter: PsiElementFilter = AnyElement, ): ProtobufElement? { scope.items { - if (it.name() == symbol.firstComponent) { + val matched = + if (it is ProtobufMultiNameDefinition) { + symbol.firstComponent in it.names() + } else { + it.name() == symbol.firstComponent + } + if (matched) { if (symbol.componentCount == 1) { return it.takeIf { filter.isAccepted(it) } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufTypeNameReference.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufTypeNameReference.kt deleted file mode 100644 index 2cf6766e..00000000 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/reference/ProtobufTypeNameReference.kt +++ /dev/null @@ -1,196 +0,0 @@ -package io.kanro.idea.plugin.protobuf.lang.reference - -import com.intellij.codeInsight.completion.CompletionUtilCore -import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.openapi.util.TextRange -import com.intellij.patterns.PlatformPatterns -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiReference -import com.intellij.psi.PsiReferenceBase -import com.intellij.psi.impl.source.resolve.ResolveCache -import com.intellij.psi.stubs.StubIndex -import com.intellij.psi.util.PsiElementFilter -import com.intellij.psi.util.QualifiedName -import com.intellij.psi.util.parentOfType -import com.intellij.util.ArrayUtilRt -import io.kanro.idea.plugin.protobuf.lang.completion.AddImportInsertHandler -import io.kanro.idea.plugin.protobuf.lang.completion.SmartInsertHandler -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcIO -import io.kanro.idea.plugin.protobuf.lang.psi.prev -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufLookupItem -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHost -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufSymbolReferenceHover -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScope -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItem -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.ShortNameIndex -import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver -import io.kanro.idea.plugin.protobuf.lang.util.AnyElement -import io.kanro.idea.plugin.protobuf.lang.util.removeCommonPrefix - -class ProtobufTypeNameReference( - element: ProtobufSymbolReferenceHost, - val hover: ProtobufSymbolReferenceHover, - val symbolIndex: Int, - val child: ProtobufTypeNameReference?, -) : PsiReferenceBase(element) { - private object Resolver : ResolveCache.Resolver { - override fun resolve( - ref: PsiReference, - incompleteCode: Boolean, - ): PsiElement? { - ref as ProtobufTypeNameReference - val resolveName = ref.hover.symbol().subQualifiedName(0, ref.symbolIndex + 1) - val filter = - when (ref.element.parent) { - is ProtobufExtensionOptionName -> ProtobufSymbolFilters.extensionOptionNameVariants(ref.element.parentOfType()) - is ProtobufFieldDefinition, - is ProtobufMapFieldDefinition, - -> ProtobufSymbolFilters.fieldTypeNameVariants - is ProtobufRpcIO -> ProtobufSymbolFilters.rpcTypeNameVariants - is ProtobufExtendDefinition -> ProtobufSymbolFilters.extendTypeNameVariants - else -> AnyElement - } - return if (ref.hover.absolutely()) { - ProtobufSymbolResolver.resolveAbsolutely(ref.element, resolveName, filter) - } else { - ProtobufSymbolResolver.resolveRelatively(ref.element, resolveName, filter) - } - } - } - - override fun resolve(): PsiElement? { - when (val childResult = child?.resolve()) { - is ProtobufScopeItem -> { - val owner = childResult.owner() - if (owner is ProtobufFile) { - return owner.packageParts().last() - } - return owner - } - is ProtobufPackageName -> return childResult.prev() - } - - return ResolveCache.getInstance(element.project) - .resolveWithCaching(this, Resolver, false, false) - } - - override fun calculateDefaultRangeInElement(): TextRange { - val part = hover.symbolParts()[symbolIndex] - return TextRange.from( - part.startOffset, - part.value.length, - ) - } - - override fun getVariants(): Array { - val result = mutableListOf() - val addedElements = mutableSetOf() - val filter = element.referencesHover()?.variantFilter() ?: return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val pattern = element.text - getVariantsInCurrentScope(pattern, filter, result, addedElements) - getVariantsInStubIndex(pattern, filter, result, addedElements) - return result.toTypedArray() - } - - private fun getVariantsInCurrentScope( - pattern: String, - filter: PsiElementFilter, - result: MutableList, - elements: MutableSet, - ) { - val targetName = pattern.substringBeforeLast('.', "").trim('.') - val targetScope = - if (targetName.isEmpty()) { - QualifiedName.fromComponents() - } else { - QualifiedName.fromDottedString(targetName) - } - if (hover.absolutely()) { - ProtobufSymbolResolver.collectAbsolute(element, targetScope, filter) - } else { - ProtobufSymbolResolver.collectRelatively(element, targetScope, filter) - }.forEach { - if (it in elements) return@forEach - result += lookupFor(it, targetScope) ?: return@forEach - elements += it - } - } - - private fun getVariantsInStubIndex( - pattern: String, - filter: PsiElementFilter, - result: MutableList, - elements: MutableSet, - ): Array { - if (pattern.contains('.')) return ArrayUtilRt.EMPTY_OBJECT_ARRAY - if (!pattern.endsWith(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED)) return ArrayUtilRt.EMPTY_OBJECT_ARRAY - val searchName = pattern.substringBefore(CompletionUtilCore.DUMMY_IDENTIFIER_TRIMMED) - val scope = ProtobufRootResolver.searchScope(element) - val matcher = PlatformPatterns.string().contains(searchName) - val currentScope = element.parentOfType()?.scope() - return StubIndex.getInstance().getAllKeys(ShortNameIndex.key, element.project).asSequence().filter { - matcher.accepts(it) - }.flatMap { - StubIndex.getElements(ShortNameIndex.key, it, element.project, scope, ProtobufElement::class.java) - .asSequence() - }.filter { - filter.isAccepted(it) - }.mapNotNull { - if (it in elements) return@mapNotNull null - result += lookupForStub(it, currentScope) ?: return@mapNotNull null - elements += it - }.toList().toTypedArray() - } - - override fun handleElementRename(newElementName: String): PsiElement { - hover.renamePart(symbolIndex, newElementName) - return element - } - - private fun lookupFor( - element: ProtobufElement, - scope: QualifiedName, - ): LookupElement? { - var builder = (element as? ProtobufLookupItem)?.lookup() ?: return null - builder = builder.withLookupString(scope.append(builder.lookupString).toString()) - if (element is ProtobufPackageName) { - builder = builder.withInsertHandler(packageInsertHandler) - } - return builder - } - - private fun lookupForStub( - element: ProtobufElement, - currentScope: QualifiedName?, - ): LookupElement? { - if (element !is ProtobufDefinition) return null - val qualifiedName = element.qualifiedName() ?: return null - - val targetName = - if (currentScope != null) { - qualifiedName.removeCommonPrefix(currentScope) - } else { - qualifiedName - } - return LookupElementBuilder.create(targetName) - .withLookupString(qualifiedName.lastComponent!!) - .withPresentableText(qualifiedName.lastComponent!!) - .withIcon(element.getIcon(false)) - .withTailText("${element.tailText() ?: ""} (${qualifiedName.removeTail(1)})", true) - .withTypeText(element.type()) - .withInsertHandler(AddImportInsertHandler(element)) - } - - companion object { - private val packageInsertHandler = SmartInsertHandler(".", 0, true) - } -} diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/support/Options.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/support/Options.kt index 778daf7a..f4817465 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/support/Options.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/support/Options.kt @@ -11,6 +11,7 @@ enum class Options(val messageName: String) { ENUM_VALUE_OPTIONS("EnumValueOptions"), SERVICE_OPTIONS("ServiceOptions"), METHOD_OPTIONS("MethodOptions"), + EXTENSION_RANGE_OPTIONS("ExtensionRangeOptions"), ; val qualifiedName by lazy { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufDocumentationProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufDocumentationProvider.kt index 3f16e228..8073f994 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufDocumentationProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufDocumentationProvider.kt @@ -6,10 +6,10 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager import com.intellij.psi.stubs.StubIndex -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocument -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufDocumented -import io.kanro.idea.plugin.protobuf.lang.psi.stub.index.QualifiedNameIndex +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentElement +import io.kanro.idea.plugin.protobuf.lang.psi.feature.DocumentOwner +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.index.QualifiedNameIndex import io.kanro.idea.plugin.protobuf.lang.psi.walkChildren import io.kanro.idea.plugin.protobuf.lang.reference.ProtobufSymbolResolver import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver @@ -21,8 +21,8 @@ class ProtobufDocumentationProvider : DocumentationProvider { element: PsiElement?, originalElement: PsiElement?, ): String? { - (originalElement as? ProtobufDocumented)?.navigateInfo()?.let { return it } - (element as? ProtobufDocumented)?.navigateInfo()?.let { return it } + (originalElement as? DocumentOwner)?.navigateInfo()?.let { return it } + (element as? DocumentOwner)?.navigateInfo()?.let { return it } return null } @@ -30,8 +30,8 @@ class ProtobufDocumentationProvider : DocumentationProvider { element: PsiElement?, originalElement: PsiElement?, ): String? { - (originalElement as? ProtobufDocumented)?.document()?.let { return it } - (element as? ProtobufDocumented)?.document()?.let { return it } + (originalElement as? DocumentOwner)?.document()?.let { return it } + (element as? DocumentOwner)?.document()?.let { return it } return null } @@ -39,8 +39,8 @@ class ProtobufDocumentationProvider : DocumentationProvider { element: PsiElement, originalElement: PsiElement?, ): String? { - (originalElement as? ProtobufDocumented)?.hoverDocument()?.let { return it } - (element as? ProtobufDocumented)?.hoverDocument()?.let { return it } + (originalElement as? DocumentOwner)?.hoverDocument()?.let { return it } + (element as? DocumentOwner)?.hoverDocument()?.let { return it } return null } @@ -60,14 +60,14 @@ class ProtobufDocumentationProvider : DocumentationProvider { } override fun generateRenderedDoc(comment: PsiDocCommentBase): String? { - return (comment as? ProtobufDocument)?.render() + return (comment as? DocumentElement)?.render() } override fun collectDocComments( file: PsiFile, sink: Consumer, ) { - file.walkChildren { + file.walkChildren { if (it.owner != null) { sink.accept(it) } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufElementDescriptionProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufElementDescriptionProvider.kt index 888e5547..e811430e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufElementDescriptionProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufElementDescriptionProvider.kt @@ -6,7 +6,7 @@ import com.intellij.psi.PsiElement import com.intellij.usageView.UsageViewLongNameLocation import com.intellij.usageView.UsageViewShortNameLocation import com.intellij.usageView.UsageViewTypeLocation -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition class ProtobufElementDescriptionProvider : ElementDescriptionProvider { override fun getElementDescription( diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufIconProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufIconProvider.kt index b2651f28..612ca202 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufIconProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufIconProvider.kt @@ -3,18 +3,18 @@ package io.kanro.idea.plugin.protobuf.lang.ui import com.intellij.ide.IconProvider import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufGroupDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufOneofDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufPackageName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufGroupDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOneofDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufPackageName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition import javax.swing.Icon class ProtobufIconProvider : IconProvider() { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufStructureViewFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufStructureViewFactory.kt index d99403eb..30b5c1cc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufStructureViewFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/ui/ProtobufStructureViewFactory.kt @@ -12,9 +12,9 @@ import com.intellij.navigation.ItemPresentation import com.intellij.openapi.editor.Editor import com.intellij.psi.NavigatablePsiElement import com.intellij.psi.PsiFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufScopeItemContainer +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufScopeItemContainer class ProtobufStructureViewFactory : PsiStructureViewFactory { override fun getStructureViewBuilder(psiFile: PsiFile): StructureViewBuilder? { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufFindUsageProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufFindUsageProvider.kt index d30e543d..48d3dc8e 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufFindUsageProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufFindUsageProvider.kt @@ -8,8 +8,8 @@ import com.intellij.psi.PsiElement import com.intellij.psi.tree.TokenSet import io.kanro.idea.plugin.protobuf.lang.ProtobufParserDefinition import io.kanro.idea.plugin.protobuf.lang.lexer.ProtobufLexer -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.token.ProtobufTokens +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.token.ProtobufTokens class ProtobufFindUsageProvider : FindUsagesProvider { override fun getWordsScanner(): WordsScanner { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufUsageTypeProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufUsageTypeProvider.kt index 43de6e2b..aa8bdd1a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufUsageTypeProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/usage/ProtobufUsageTypeProvider.kt @@ -4,37 +4,34 @@ import com.intellij.psi.PsiElement import com.intellij.usages.impl.rules.UsageType import com.intellij.usages.impl.rules.UsageTypeProvider import io.kanro.idea.plugin.protobuf.ProtobufBundle -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufBuiltInOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtendDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufExtensionOptionName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFieldName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMapFieldDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcIO -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufSymbolName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufExtendDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMapFieldDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufOptionName +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcIO +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufTypeName +import io.kanro.idea.plugin.protobuf.lang.psi.text.ProtoTextFieldName class ProtobufUsageTypeProvider : UsageTypeProvider { override fun getUsageType(element: PsiElement): UsageType? { return when (element) { - is ProtobufFieldName -> ASSIGN_USAGE_TYPE - is ProtobufBuiltInOptionName -> OPTION_USAGE_TYPE - is ProtobufSymbolName -> - when (element.parent.parent) { + is ProtoTextFieldName -> ASSIGN_USAGE_TYPE + is ProtobufOptionName -> OPTION_USAGE_TYPE + is ProtobufTypeName -> + when (element.parent) { is ProtobufRpcIO -> METHOD_PARAMETER_USAGE_TYPE - is ProtobufExtensionOptionName -> OPTION_USAGE_TYPE is ProtobufFieldDefinition, is ProtobufMapFieldDefinition -> FIELD_DECLARATION_USAGE_TYPE is ProtobufExtendDefinition -> EXTEND_DECLARATION_USAGE_TYPE else -> null } + else -> null } } - - companion object { - val FIELD_DECLARATION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.field.declaration")) - val METHOD_PARAMETER_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.method.parameter")) - val EXTEND_DECLARATION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.extend.declaration")) - val OPTION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.option")) - val ASSIGN_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.assign")) - } } + +val FIELD_DECLARATION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.field.declaration")) +val METHOD_PARAMETER_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.method.parameter")) +val EXTEND_DECLARATION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.extend.declaration")) +val OPTION_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.option")) +val ASSIGN_USAGE_TYPE = UsageType(ProtobufBundle.messagePointer("usage.type.assign")) diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/CommonMark.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/CommonMark.kt index 5ddfdfa0..ff1dbd0b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/CommonMark.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/lang/util/CommonMark.kt @@ -1,7 +1,7 @@ package io.kanro.idea.plugin.protobuf.lang.util import com.intellij.codeInsight.documentation.DocumentationManagerProtocol -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement import org.commonmark.ext.autolink.AutolinkExtension import org.commonmark.ext.gfm.tables.TablesExtension import org.commonmark.internal.InlineParserImpl diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcEndpointsProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcEndpointsProvider.kt index cc7fe265..01f4410c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcEndpointsProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcEndpointsProvider.kt @@ -19,7 +19,7 @@ import com.intellij.psi.search.GlobalSearchScope import io.kanro.idea.plugin.protobuf.ProtobufIcons import io.kanro.idea.plugin.protobuf.lang.ProtobufFileType import io.kanro.idea.plugin.protobuf.lang.ProtobufLanguage -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile import io.kanro.idea.plugin.protobuf.microservices.model.ProtobufRpcModel import io.kanro.idea.plugin.protobuf.microservices.model.ProtobufServiceModel @@ -49,7 +49,7 @@ class GrpcEndpointsProvider : EndpointsUrlTargetProvider { return when (filter) { is SearchScopeEndpointsFilter -> { - val scope = filter.searchScope + val scope = filter.contentSearchScope FileTypeIndex.getFiles(ProtobufFileType.INSTANCE, scope).flatMap { val psi = PsiManager.getInstance(project).findFile(it) as? ProtobufFile diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcUrlTargetInfo.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcUrlTargetInfo.kt index fa07bbd0..be4fc7fd 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcUrlTargetInfo.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/GrpcUrlTargetInfo.kt @@ -5,7 +5,7 @@ import com.intellij.microservices.url.UrlPath import com.intellij.microservices.url.UrlTargetInfo import com.intellij.psi.PsiElement import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition import javax.swing.Icon @Suppress("UnstableApiUsage") diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufRpcModel.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufRpcModel.kt index b87f8205..bc7f2efa 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufRpcModel.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufRpcModel.kt @@ -1,7 +1,7 @@ package io.kanro.idea.plugin.protobuf.microservices.model import com.intellij.psi.SmartPsiElementPointer -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition class ProtobufRpcModel(private val pointer: SmartPsiElementPointer) { fun getPsi(): ProtobufRpcDefinition? { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufServiceModel.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufServiceModel.kt index 1ed61ba2..1e14bc1b 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufServiceModel.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/microservices/model/ProtobufServiceModel.kt @@ -2,8 +2,8 @@ package io.kanro.idea.plugin.protobuf.microservices.model import com.intellij.psi.SmartPointerManager import com.intellij.psi.SmartPsiElementPointer -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class ProtobufServiceModel(private val pointer: SmartPsiElementPointer) { fun getMethods(): List { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Extensions.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Extensions.kt index 35a51c35..640dd7de 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Extensions.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Extensions.kt @@ -9,12 +9,12 @@ import com.intellij.psi.search.GlobalSearchScope import io.kanro.idea.plugin.protobuf.java.findJavaClass import io.kanro.idea.plugin.protobuf.java.fullClassName import io.kanro.idea.plugin.protobuf.java.getterName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike fun ProtobufMessageDefinition.toClass(): PsiClass? { return findJavaClass(fullClassName()) @@ -56,6 +56,7 @@ fun ProtobufFieldLike.toGetters(): Array { is ProtobufMessageDefinition -> owner.toMutableClass()?.findMethodsByName(getterName(), true) ?: PsiMethod.EMPTY_ARRAY + else -> PsiMethod.EMPTY_ARRAY } } @@ -65,6 +66,7 @@ fun ProtobufFieldLike.toSetters(): Array { is ProtobufMessageDefinition -> owner.toMutableClass()?.findMethodsByName(getterName(), true) ?: PsiMethod.EMPTY_ARRAY + else -> PsiMethod.EMPTY_ARRAY } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Names.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Names.kt index 0596344f..f502253a 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Names.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/Names.kt @@ -3,20 +3,19 @@ package io.kanro.idea.plugin.protobuf.sisyphus import com.intellij.psi.util.QualifiedName import io.kanro.idea.plugin.protobuf.java.javaPackage import io.kanro.idea.plugin.protobuf.java.jsonName -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufFile -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufFileStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufEnumValueStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufMessageStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.primitive.ProtobufFieldLikeStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufFile +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufEnumValueStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufMessageStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.primitive.ProtobufFieldLikeStub import io.kanro.idea.plugin.protobuf.lang.util.toQualifiedName import io.kanro.idea.plugin.protobuf.string.toCamelCase import io.kanro.idea.plugin.protobuf.string.toScreamingSnakeCase @@ -25,7 +24,7 @@ fun ProtobufFile.fullPackageName(): QualifiedName? { return javaPackage()?.toQualifiedName() ?: scope() } -fun ProtobufFileStub.fullPackageName(): QualifiedName? { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.fullPackageName(): QualifiedName? { return javaPackage()?.toQualifiedName() ?: scope() } @@ -33,7 +32,7 @@ fun ProtobufFile.fullInternalPackageName(): QualifiedName { return fullPackageName()?.append("internal") ?: QualifiedName.fromComponents("internal") } -fun ProtobufFileStub.fullInternalPackageName(): QualifiedName { +fun io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufFileStub.fullInternalPackageName(): QualifiedName { return fullPackageName()?.append("internal") ?: QualifiedName.fromComponents("internal") } @@ -60,6 +59,7 @@ fun ProtobufMessageDefinition.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -71,6 +71,7 @@ fun ProtobufMessageStub.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -81,6 +82,7 @@ fun ProtobufMessageDefinition.fullMutableClassName(): QualifiedName? { is ProtobufMessageDefinition -> owner.fullClassName()?.append(mutableClassName()) ?: QualifiedName.fromComponents(mutableClassName()) + else -> null } } @@ -91,6 +93,7 @@ fun ProtobufMessageStub.fullMutableClassName(): QualifiedName? { is ProtobufMessageDefinition -> owner.fullClassName()?.append(mutableClassName()) ?: QualifiedName.fromComponents(mutableClassName()) + else -> null } } @@ -166,6 +169,7 @@ fun ProtobufEnumDefinition.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } @@ -177,6 +181,7 @@ fun ProtobufEnumStub.fullClassName(): QualifiedName? { owner.fullClassName()?.append(className()) ?: QualifiedName.fromComponents( className(), ) + else -> null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusFindUsageFactory.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusFindUsageFactory.kt index 7536b047..8b67523d 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusFindUsageFactory.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusFindUsageFactory.kt @@ -3,13 +3,13 @@ package io.kanro.idea.plugin.protobuf.sisyphus import com.intellij.find.findUsages.FindUsagesHandler import com.intellij.find.findUsages.FindUsagesHandlerFactory import com.intellij.psi.PsiElement -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufEnumValueDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufMessageDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.structure.ProtobufFieldLike +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufEnumValueDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufMessageDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.structure.ProtobufFieldLike class SisyphusFindUsageFactory : FindUsagesHandlerFactory() { override fun canFindUsages(element: PsiElement): Boolean { @@ -28,30 +28,36 @@ class SisyphusFindUsageFactory : FindUsagesHandlerFactory() { is ProtobufMessageDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toClass()).toTypedArray()) } + is ProtobufEnumDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toClass()).toTypedArray()) } + is ProtobufServiceDefinition -> { ProtoDefinitionFindUsage( element, listOfNotNull(element.toClass(), element.toClientClass()).toTypedArray(), ) } + is ProtobufEnumValueDefinition -> { ProtoDefinitionFindUsage(element, listOfNotNull(element.toEnumConstant()).toTypedArray()) } + is ProtobufRpcDefinition -> { ProtoDefinitionFindUsage( element, listOfNotNull(element.toMethod(), element.toClientMethod()).toTypedArray(), ) } + is ProtobufFieldLike -> { ProtoDefinitionFindUsage( element, (element.toGetters() + element.toSetters()) as Array, ) } + else -> null } } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusIndexProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusIndexProvider.kt index 6b61c347..b6942ea3 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusIndexProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusIndexProvider.kt @@ -1,14 +1,13 @@ package io.kanro.idea.plugin.protobuf.sisyphus import com.intellij.psi.stubs.IndexSink -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.feature.ProtobufIndexProvider -import io.kanro.idea.plugin.protobuf.lang.psi.stub.ProtobufStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufRpcStub -import io.kanro.idea.plugin.protobuf.lang.psi.stub.impl.ProtobufServiceStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.feature.ProtobufIndexProvider +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufRpcStub +import io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.impl.ProtobufServiceStub class SisyphusIndexProvider : ProtobufIndexProvider { override fun buildIndex( - stub: ProtobufStub<*>, + stub: io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.ProtobufStub<*>, sink: IndexSink, ) { when (stub) { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusKotlinLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusKotlinLineMarkerProvider.kt index 4ac814bd..c138bb77 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusKotlinLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusKotlinLineMarkerProvider.kt @@ -8,10 +8,10 @@ import com.intellij.psi.stubs.StubIndex import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.psi.firstLeaf -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition import io.kanro.idea.plugin.protobuf.lang.root.ProtobufRootResolver import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.uast.UClass @@ -35,6 +35,7 @@ class SisyphusKotlinLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implementing") result.add(builder.createLineMarkerInfo(element.firstLeaf())) } + is UMethod -> { val method = findMethodProtobufDefinition(parent) ?: return val builder: NavigationGutterIconBuilder = diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusNameIndex.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusNameIndex.kt index d3110eba..409d100c 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusNameIndex.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusNameIndex.kt @@ -2,7 +2,7 @@ package io.kanro.idea.plugin.protobuf.sisyphus import com.intellij.psi.stubs.StringStubIndexExtension import com.intellij.psi.stubs.StubIndexKey -import io.kanro.idea.plugin.protobuf.lang.psi.primitive.ProtobufElement +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufElement class SisyphusNameIndex : StringStubIndexExtension() { override fun getKey(): StubIndexKey { diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusProtobufLineMarkerProvider.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusProtobufLineMarkerProvider.kt index 942666a3..ae0c65c6 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusProtobufLineMarkerProvider.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/sisyphus/SisyphusProtobufLineMarkerProvider.kt @@ -7,9 +7,9 @@ import com.intellij.psi.PsiElement import com.intellij.psi.search.searches.DirectClassInheritorsSearch import com.intellij.psi.search.searches.OverridingMethodsSearch import io.kanro.idea.plugin.protobuf.ProtobufIcons -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufIdentifier -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufRpcDefinition -import io.kanro.idea.plugin.protobuf.lang.psi.ProtobufServiceDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufIdentifier +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufRpcDefinition +import io.kanro.idea.plugin.protobuf.lang.psi.proto.ProtobufServiceDefinition class SisyphusProtobufLineMarkerProvider : RelatedItemLineMarkerProvider() { override fun collectNavigationMarkers( @@ -28,6 +28,7 @@ class SisyphusProtobufLineMarkerProvider : RelatedItemLineMarkerProvider() { .setTooltipText("Implemented") result.add(builder.createLineMarkerInfo(element.identifierLiteral ?: element)) } + is ProtobufServiceDefinition -> { val clazz = owner.toClass() ?: return val apis = DirectClassInheritorsSearch.search(clazz).findAll().toList() diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/Util.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/Util.kt index 0b494e5b..4749c468 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/Util.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/Util.kt @@ -71,6 +71,7 @@ fun CharSequence.lineCommentRanges(): List { start = pos } } + else -> { start = pos pos++ @@ -85,6 +86,7 @@ fun CharSequence.lineCommentRanges(): List { } start = null } + else -> { pos++ } diff --git a/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/case/CommonWordSplitter.kt b/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/case/CommonWordSplitter.kt index 83a39763..bc998cdc 100644 --- a/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/case/CommonWordSplitter.kt +++ b/src/main/kotlin/io/kanro/idea/plugin/protobuf/string/case/CommonWordSplitter.kt @@ -23,15 +23,19 @@ object CommonWordSplitter : WordSplitter { ch.isDigit() -> { handleDigital(string, pos, stack, result) } + ch.isLowerCase() -> { handleLowerCase(string, pos, stack, result) } + ch.isUpperCase() -> { handleUpperCase(string, pos, stack, result) } + ch.isDelimiter() -> { handleDelimiter(string, pos, stack, result) } + else -> { handleUnknown(string, pos, stack, result) } @@ -55,11 +59,13 @@ object CommonWordSplitter : WordSplitter { digital.append(ch) index++ } + ch.isUpperCase() -> { digital.append(ch) index++ return handleUpperCaseAfterDigital(string, index, stack, digital, result) } + ch.isLowerCase() -> { digital.append(ch) index++ @@ -73,6 +79,7 @@ object CommonWordSplitter : WordSplitter { handleLowerCase(string, index, stack, result) } } + else -> { stack.append(digital) return entryPoint(string, index, stack, result) @@ -96,9 +103,11 @@ object CommonWordSplitter : WordSplitter { stack.append(ch) index++ } + ch.isDigit() -> { return handleDigital(string, index, stack, result) } + else -> { return entryPoint(string, index, stack, result) } @@ -121,6 +130,7 @@ object CommonWordSplitter : WordSplitter { stack.append(ch) index++ } + ch.isLowerCase() -> { val last = stack.last() stack.deleteCharAt(stack.length - 1) @@ -128,9 +138,11 @@ object CommonWordSplitter : WordSplitter { stack.append(last) return handleLowerCase(string, index, stack, result) } + ch.isDigit() -> { return handleDigital(string, index, stack, result) } + else -> { return entryPoint(string, index, stack, result) } @@ -154,6 +166,7 @@ object CommonWordSplitter : WordSplitter { digital.append(ch) index++ } + ch.isLowerCase() -> { val last = digital.last() digital.deleteCharAt(digital.length - 1) @@ -169,6 +182,7 @@ object CommonWordSplitter : WordSplitter { stack.append(last) return handleLowerCase(string, index, stack, result) } + else -> { if (!digital.last().isDigit()) { result.append(stack) @@ -194,6 +208,7 @@ object CommonWordSplitter : WordSplitter { ch.isUpperCase() || ch.isLowerCase() || ch.isDigit() || ch.isDelimiter() -> { return entryPoint(string, index, stack, result) } + else -> { stack.append(ch) index++ @@ -216,6 +231,7 @@ object CommonWordSplitter : WordSplitter { ch.isDelimiter() -> { index++ } + else -> { return entryPoint(string, index, stack, result) } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index ec08fe3b..13585f5c 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -26,15 +26,15 @@ dynamic="true" name="rootProvider"/> + - - @@ -78,9 +76,9 @@ + implementationClass="io.kanro.idea.plugin.protobuf.lang.highlight.ProtobufHighlighter"/> - @@ -135,13 +133,15 @@ + - - - + class="io.kanro.idea.plugin.protobuf.lang.psi.proto.stub.type.ProtobufStubTypes"/> + + + + + + + + + + + + + + + + + + + + - - - - + + + + - + - - - - + + + + - + diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/procedureHttp_dark.svg b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/procedureHttp_dark.svg index 6ba60f08..80050c63 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/procedureHttp_dark.svg +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/procedureHttp_dark.svg @@ -1,6 +1,7 @@ - + @@ -14,7 +15,8 @@ - + diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file.svg b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file.svg new file mode 100644 index 00000000..e76202b2 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file_dark.svg b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file_dark.svg new file mode 100644 index 00000000..80050c63 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/expui/protobuf_text_file_dark.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/icon/protobuf_text_file.svg b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/protobuf_text_file.svg new file mode 100644 index 00000000..b0327051 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/icon/protobuf_text_file.svg @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/any.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/any.proto index f14a478e..4387d3a0 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/any.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/any.proto @@ -32,12 +32,12 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/anypb"; option java_package = "com.google.protobuf"; option java_outer_classname = "AnyProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // `Any` contains an arbitrary serialized protocol buffer message along with a // URL that describes the type of the serialized message. @@ -63,6 +63,10 @@ option objc_class_prefix = "GPB"; // if (any.is(Foo.class)) { // foo = any.unpack(Foo.class); // } +// // or ... +// if (any.isSameTypeAs(Foo.getDefaultInstance())) { +// foo = any.unpack(Foo.getDefaultInstance()); +// } // // Example 3: Pack and unpack a message in Python. // @@ -93,7 +97,6 @@ option objc_class_prefix = "GPB"; // in the type URL, for example "foo.bar.com/x/y.z" will yield type // name "y.z". // -// // JSON // ==== // The JSON representation of an `Any` value uses the regular @@ -146,7 +149,8 @@ message Any { // // Note: this functionality is not currently available in the official // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. + // type.googleapis.com. As of May 2023, there are no widely used type server + // implementations and no plans to implement one. // // Schemes other than `http`, `https` (or the empty scheme) might be // used with implementation specific semantics. diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/api.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/api.proto index 27da82a8..dc4ac4b3 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/api.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/api.proto @@ -35,11 +35,11 @@ package google.protobuf; import "google/protobuf/source_context.proto"; import "google/protobuf/type.proto"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option java_package = "com.google.protobuf"; option java_outer_classname = "ApiProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/apipb"; // Api is a light-weight descriptor for an API Interface. @@ -82,7 +82,6 @@ message Api { // be omitted. Zero major versions must only be used for // experimental, non-GA interfaces. // - // string version = 4; // Source context for the protocol buffer service represented by this @@ -167,7 +166,7 @@ message Method { // The mixin construct implies that all methods in `AccessControl` are // also declared with same name and request/response types in // `Storage`. A documentation generator or annotation processor will -// see the effective `Storage.GetAcl` method after inheriting +// see the effective `Storage.GetAcl` method after inherting // documentation and annotations as follows: // // service Storage { diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/cpp_features.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/cpp_features.proto new file mode 100644 index 00000000..00134599 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/cpp_features.proto @@ -0,0 +1,58 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package pb; + +import "google/protobuf/descriptor.proto"; + +extend google.protobuf.FeatureSet { + optional CppFeatures cpp = 1000; +} + +message CppFeatures { + // Whether or not to treat an enum field as closed. This option is only + // applicable to enum fields, and will be removed in the future. It is + // consistent with the legacy behavior of using proto3 enum types for proto2 + // fields. + optional bool legacy_closed_enum = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2023, + deprecation_warning: "The legacy closed enum treatment in C++ is " + "deprecated and is scheduled to be removed in " + "edition 2025. Mark enum type on the enum " + "definitions themselves rather than on fields.", + }, + edition_defaults = {edition: EDITION_PROTO2, value: "true"}, + edition_defaults = {edition: EDITION_PROTO3, value: "false"} + ]; + + enum StringType { + STRING_TYPE_UNKNOWN = 0; + VIEW = 1; + CORD = 2; + STRING = 3; + } + + optional StringType string_type = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "STRING"}, + edition_defaults = {edition: EDITION_2024, value: "VIEW"} + ]; +} diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/descriptor.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/descriptor.proto index 1e276a96..11ec2bf6 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/descriptor.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/descriptor.proto @@ -36,7 +36,6 @@ // A valid .proto file can be translated directly to a FileDescriptorProto // without any other information (e.g. without reading its imports). - syntax = "proto2"; package google.protobuf; @@ -58,6 +57,42 @@ message FileDescriptorSet { repeated FileDescriptorProto file = 1; } +// The full set of known editions. +enum Edition { + // A placeholder for an unknown edition value. + EDITION_UNKNOWN = 0; + + // A placeholder edition for specifying default behaviors *before* a feature + // was first introduced. This is effectively an "infinite past". + EDITION_LEGACY = 900; + + // Legacy syntax "editions". These pre-date editions, but behave much like + // distinct editions. These can't be used to specify the edition of proto + // files, but feature definitions must supply proto2/proto3 defaults for + // backwards compatibility. + EDITION_PROTO2 = 998; + EDITION_PROTO3 = 999; + + // Editions that have been released. The specific values are arbitrary and + // should not be depended on, but they will always be time-ordered for easy + // comparison. + EDITION_2023 = 1000; + EDITION_2024 = 1001; + + // Placeholder editions for testing feature resolution. These should not be + // used or relyed on outside of tests. + EDITION_1_TEST_ONLY = 1; + EDITION_2_TEST_ONLY = 2; + EDITION_99997_TEST_ONLY = 99997; + EDITION_99998_TEST_ONLY = 99998; + EDITION_99999_TEST_ONLY = 99999; + + // Placeholder for specifying unbounded edition support. This should only + // ever be used by plugins that can expect to never require any changes to + // support a new edition. + EDITION_MAX = 0x7FFFFFFF; +} + // Describes a complete .proto file. message FileDescriptorProto { optional string name = 1; // file name, relative to root of source tree @@ -86,8 +121,13 @@ message FileDescriptorProto { optional SourceCodeInfo source_code_info = 9; // The syntax of the proto file. - // The supported values are "proto2" and "proto3". + // The supported values are "proto2", "proto3", and "editions". + // + // If `edition` is present, this value must be "editions". optional string syntax = 12; + + // The edition of the proto file. + optional Edition edition = 14; } // Describes a message type. @@ -129,6 +169,51 @@ message ExtensionRangeOptions { // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; + message Declaration { + // The extension number declared within the extension range. + optional int32 number = 1; + + // The fully-qualified name of the extension field. There must be a leading + // dot in front of the full name. + optional string full_name = 2; + + // The fully-qualified type name of the extension field. Unlike + // Metadata.type, Declaration.type must have a leading dot for messages + // and enums. + optional string type = 3; + + // If true, indicates that the number is reserved in the extension range, + // and any extension field with the number will fail to compile. Set this + // when a declared extension field is deleted. + optional bool reserved = 5; + + // If true, indicates that the extension must be defined as repeated. + // Otherwise the extension must be defined as optional. + optional bool repeated = 6; + + reserved 4; // removed is_repeated + } + + // For external users: DO NOT USE. We are in the process of open sourcing + // extension declaration and executing internal cleanups before it can be + // used externally. + repeated Declaration declaration = 2 [retention = RETENTION_SOURCE]; + + // Any features defined in the specific edition. + optional FeatureSet features = 50; + + // The verification state of the extension range. + enum VerificationState { + // All the extensions of the range must be declared. + DECLARATION = 0; + UNVERIFIED = 1; + } + + // The verification state of the range. + // TODO: flip the default to DECLARATION once all empty ranges + // are marked as UNVERIFIED. + optional VerificationState verification = 3 + [default = UNVERIFIED, retention = RETENTION_SOURCE]; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; @@ -153,9 +238,10 @@ message FieldDescriptorProto { TYPE_BOOL = 8; TYPE_STRING = 9; // Tag-delimited aggregate. - // Group type is deprecated and not supported in proto3. However, Proto3 + // Group type is deprecated and not supported after google.protobuf. However, Proto3 // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. + // treat group fields as unknown fields. In Editions, the group wire format + // can be enabled via the `message_encoding` feature. TYPE_GROUP = 10; TYPE_MESSAGE = 11; // Length-delimited aggregate. @@ -172,8 +258,11 @@ message FieldDescriptorProto { enum Label { // 0 is reserved for errors LABEL_OPTIONAL = 1; - LABEL_REQUIRED = 2; LABEL_REPEATED = 3; + // The required label is only allowed in google.protobuf. In proto3 and Editions + // it's explicitly prohibited. In Editions, the `field_presence` feature + // can be used to get this behavior. + LABEL_REQUIRED = 2; } optional string name = 1; @@ -199,7 +288,6 @@ message FieldDescriptorProto { // For booleans, "true" or "false". // For strings, contains the default text contents (not escaped in any way). // For bytes, contains the C escaped value. All bytes >= 128 are escaped. - // TODO(kenton): Base-64 encode? optional string default_value = 7; // If set, gives the index of a oneof in the containing type's oneof_decl @@ -217,12 +305,12 @@ message FieldDescriptorProto { // If true, this is a proto3 "optional". When a proto3 field is optional, it // tracks presence regardless of field type. // - // When proto3_optional is true, this field must be belong to a oneof to - // signal to old proto3 clients that presence is tracked for this field. This - // oneof is known as a "synthetic" oneof, and this field must be its sole - // member (each proto3 optional field gets its own synthetic oneof). Synthetic - // oneofs exist in the descriptor only, and do not generate any API. Synthetic - // oneofs must be ordered after all "real" oneofs. + // When proto3_optional is true, this field must belong to a oneof to signal + // to old proto3 clients that presence is tracked for this field. This oneof + // is known as a "synthetic" oneof, and this field must be its sole member + // (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs + // exist in the descriptor only, and do not generate any API. Synthetic oneofs + // must be ordered after all "real" oneofs. // // For message fields, proto3_optional doesn't create any semantic change, // since non-repeated message fields always track presence. However it still @@ -306,7 +394,6 @@ message MethodDescriptorProto { optional bool server_streaming = 6 [default = false]; } - // =================================================================== // Options @@ -347,7 +434,6 @@ message FileOptions { // domain names. optional string java_package = 1; - // Controls the name of the wrapper Java class generated for the .proto file. // That class will always contain the .proto file's getDescriptor() method as // well as any top-level extensions defined in the .proto file. @@ -366,15 +452,18 @@ message FileOptions { // This option does nothing. optional bool java_generate_equals_and_hash = 20 [deprecated = true]; - // If set true, then the Java2 code generator will generate code that - // throws an exception whenever an attempt is made to assign a non-UTF-8 - // byte sequence to a string field. - // Message reflection will do the same. - // However, an extension field still accepts non-UTF-8 byte sequences. - // This option has no effect on when used with the lite runtime. + // A proto2 file can set this to true to opt in to UTF-8 checking for Java, + // which will throw an exception if invalid UTF-8 is parsed from the wire or + // assigned to a string field. + // + // TODO: clarify exactly what kinds of field types this option + // applies to, and update these docs accordingly. + // + // Proto3 files already perform these checks. Setting the option explicitly to + // false has no effect: it cannot be used to opt proto3 files out of UTF-8 + // checks. optional bool java_string_check_utf8 = 27 [default = false]; - // Generated classes can be optimized for speed or code size. enum OptimizeMode { SPEED = 1; // Generate complete code for parsing, serialization, @@ -391,9 +480,6 @@ message FileOptions { // - Otherwise, the basename of the .proto file, without extension. optional string go_package = 11; - - - // Should generic services be generated in each language? "Generic" services // are not specific to any particular RPC system. They are generated by the // main code generators in each language (without additional plugins). @@ -407,7 +493,8 @@ message FileOptions { optional bool cc_generic_services = 16 [default = false]; optional bool java_generic_services = 17 [default = false]; optional bool py_generic_services = 18 [default = false]; - optional bool php_generic_services = 42 [default = false]; + reserved 42; // removed php_generic_services + reserved "php_generic_services"; // Is this file deprecated? // Depending on the target platform, this can emit Deprecated annotations @@ -419,7 +506,6 @@ message FileOptions { // only to generated classes for C++. optional bool cc_enable_arenas = 31 [default = true]; - // Sets the objective c class prefix which is prepended to all objective c // generated classes from this .proto. There is no default. optional string objc_class_prefix = 36; @@ -452,6 +538,8 @@ message FileOptions { // determining the ruby package. optional string ruby_package = 45; + // Any features defined in the specific edition. + optional FeatureSet features = 50; // The parser stores options it doesn't recognize here. // See the documentation for the "Options" section above. @@ -524,6 +612,20 @@ message MessageOptions { reserved 8; // javalite_serializable reserved 9; // javanano_as_lite + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // + // This should only be used as a temporary measure against broken builds due + // to the change in behavior for JSON field name conflicts. + // + // TODO This is legacy behavior we plan to remove once downstream + // teams have had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; + + // Any features defined in the specific edition. + optional FeatureSet features = 12; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -535,13 +637,21 @@ message MessageOptions { message FieldOptions { // The ctype option instructs the C++ code generator to use a different // representation of the field than it normally would. See the specific - // options below. This option is not yet implemented in the open source - // release -- sorry, we'll try to include it in a future version! + // options below. This option is only implemented to support use of + // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of + // type "bytes" in the open source release -- sorry, we'll try to include + // other types in a future version! optional CType ctype = 1 [default = STRING]; enum CType { // Default mode. STRING = 0; + // The option [ctype=CORD] may be applied to a non-repeated field of type + // "bytes". It indicates that in C++, the data should be stored in a Cord + // instead of a string. For very large strings, this may reduce memory + // fragmentation. It may also allow better performance when parsing from a + // Cord, or when parsing with aliasing enabled, as the parsed Cord may then + // alias the original buffer. CORD = 1; STRING_PIECE = 2; @@ -550,7 +660,9 @@ message FieldOptions { // a more efficient representation on the wire. Rather than repeatedly // writing the tag and type for each element, the entire array is encoded as // a single length-delimited blob. In proto3, only explicit setting it to - // false will avoid using packed encoding. + // false will avoid using packed encoding. This option is prohibited in + // Editions, but the `repeated_field_encoding` feature can be used to control + // the behavior. optional bool packed = 2; // The jstype option determines the JavaScript type used for values of the @@ -593,19 +705,18 @@ message FieldOptions { // call from multiple threads concurrently, while non-const methods continue // to require exclusive access. // - // - // Note that implementations may choose not to check required fields within - // a lazy sub-message. That is, calling IsInitialized() on the outer message - // may return true even if the inner message has missing required fields. - // This is necessary because otherwise the inner message would have to be - // parsed in order to perform the check, defeating the purpose of lazy - // parsing. An implementation which chooses not to check required fields - // must be consistent about it. That is, for any particular sub-message, the - // implementation must either *always* check its required fields, or *never* - // check its required fields, regardless of whether or not the message has - // been parsed. + // Note that lazy message fields are still eagerly verified to check + // ill-formed wireformat or missing required fields. Calling IsInitialized() + // on the outer message would fail if the inner message has missing required + // fields. Failed verification would result in parsing failure (except when + // uninitialized messages are acceptable). optional bool lazy = 5 [default = false]; + // unverified_lazy does no correctness checks on the byte stream. This should + // only be used where lazy with verification is prohibitive for performance + // reasons. + optional bool unverified_lazy = 15 [default = false]; + // Is this field deprecated? // Depending on the target platform, this can emit Deprecated annotations // for accessors, or it will be completely ignored; in the very least, this @@ -615,6 +726,70 @@ message FieldOptions { // For Google-internal migration only. Do not use. optional bool weak = 10 [default = false]; + // Indicate that the field value should not be printed out when using debug + // formats, e.g. when the field contains sensitive credentials. + optional bool debug_redact = 16 [default = false]; + + // If set to RETENTION_SOURCE, the option will be omitted from the binary. + // Note: as of January 2023, support for this is in progress and does not yet + // have an effect (b/264593489). + enum OptionRetention { + RETENTION_UNKNOWN = 0; + RETENTION_RUNTIME = 1; + RETENTION_SOURCE = 2; + } + + optional OptionRetention retention = 17; + + // This indicates the types of entities that the field may apply to when used + // as an option. If it is unset, then the field may be freely used as an + // option on any kind of entity. Note: as of January 2023, support for this is + // in progress and does not yet have an effect (b/264593489). + enum OptionTargetType { + TARGET_TYPE_UNKNOWN = 0; + TARGET_TYPE_FILE = 1; + TARGET_TYPE_EXTENSION_RANGE = 2; + TARGET_TYPE_MESSAGE = 3; + TARGET_TYPE_FIELD = 4; + TARGET_TYPE_ONEOF = 5; + TARGET_TYPE_ENUM = 6; + TARGET_TYPE_ENUM_ENTRY = 7; + TARGET_TYPE_SERVICE = 8; + TARGET_TYPE_METHOD = 9; + } + + repeated OptionTargetType targets = 19; + + message EditionDefault { + optional Edition edition = 3; + optional string value = 2; // Textproto value. + } + repeated EditionDefault edition_defaults = 20; + + // Any features defined in the specific edition. + optional FeatureSet features = 21; + + // Information about the support window of a feature. + message FeatureSupport { + // The edition that this feature was first available in. In editions + // earlier than this one, the default assigned to EDITION_LEGACY will be + // used, and proto files will not be able to override it. + optional Edition edition_introduced = 1; + + // The edition this feature becomes deprecated in. Using this after this + // edition may trigger warnings. + optional Edition edition_deprecated = 2; + + // The deprecation warning text if this feature is used after the edition it + // was marked deprecated in. + optional string deprecation_warning = 3; + + // The edition this feature is no longer available in. In editions after + // this one, the last default assigned will be used, and proto files will + // not be able to override it. + optional Edition edition_removed = 4; + } + optional FeatureSupport feature_support = 22; // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -622,10 +797,14 @@ message FieldOptions { // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; - reserved 4; // removed jtype + reserved 4; // removed jtype + reserved 18; // reserve target, target_obsolete_do_not_use } message OneofOptions { + // Any features defined in the specific edition. + optional FeatureSet features = 1; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -647,6 +826,17 @@ message EnumOptions { reserved 5; // javanano_as_lite + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // TODO Remove this legacy behavior once downstream teams have + // had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; + + // Any features defined in the specific edition. + optional FeatureSet features = 7; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -661,6 +851,17 @@ message EnumValueOptions { // this is a formalization for deprecating enum values. optional bool deprecated = 1 [default = false]; + // Any features defined in the specific edition. + optional FeatureSet features = 2; + + // Indicate that fields annotated with this enum value should not be printed + // out when using debug formats, e.g. when the field contains sensitive + // credentials. + optional bool debug_redact = 3 [default = false]; + + // Information about the support window of a feature value. + optional FieldOptions.FeatureSupport feature_support = 4; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -670,6 +871,9 @@ message EnumValueOptions { message ServiceOptions { + // Any features defined in the specific edition. + optional FeatureSet features = 34; + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC // framework. We apologize for hoarding these numbers to ourselves, but // we were already using them long before we decided to release Protocol @@ -712,6 +916,9 @@ message MethodOptions { optional IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN]; + // Any features defined in the specific edition. + optional FeatureSet features = 35; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -719,7 +926,6 @@ message MethodOptions { extensions 1000 to max; } - // A message representing a option the parser does not recognize. This only // appears in options protos created by the compiler::Parser class. // DescriptorPool resolves these when building Descriptor objects. Therefore, @@ -730,8 +936,8 @@ message UninterpretedOption { // The name of the uninterpreted option. Each string represents a segment in // a dot-separated name. is_extension is true iff a segment represents an // extension (denoted with parentheses in options specs in .proto files). - // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents - // "foo.(bar.baz).qux". + // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents + // "foo.(bar.baz).moo". message NamePart { required string name_part = 1; required bool is_extension = 2; @@ -748,6 +954,178 @@ message UninterpretedOption { optional string aggregate_value = 8; } +// =================================================================== +// Features + +// TODO Enums in C++ gencode (and potentially other languages) are +// not well scoped. This means that each of the feature enums below can clash +// with each other. The short names we've chosen maximize call-site +// readability, but leave us very open to this scenario. A future feature will +// be designed and implemented to handle this, hopefully before we ever hit a +// conflict here. +message FeatureSet { + enum FieldPresence { + FIELD_PRESENCE_UNKNOWN = 0; + EXPLICIT = 1; + IMPLICIT = 2; + LEGACY_REQUIRED = 3; + } + optional FieldPresence field_presence = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "EXPLICIT"}, + edition_defaults = {edition: EDITION_PROTO3, value: "IMPLICIT"}, + edition_defaults = {edition: EDITION_2023, value: "EXPLICIT"} + ]; + + enum EnumType { + ENUM_TYPE_UNKNOWN = 0; + OPEN = 1; + CLOSED = 2; + } + optional EnumType enum_type = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "CLOSED"}, + edition_defaults = {edition: EDITION_PROTO3, value: "OPEN"} + ]; + + enum RepeatedFieldEncoding { + REPEATED_FIELD_ENCODING_UNKNOWN = 0; + PACKED = 1; + EXPANDED = 2; + } + optional RepeatedFieldEncoding repeated_field_encoding = 3 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "EXPANDED"}, + edition_defaults = {edition: EDITION_PROTO3, value: "PACKED"} + ]; + + enum Utf8Validation { + UTF8_VALIDATION_UNKNOWN = 0; + VERIFY = 2; + NONE = 3; + reserved 1; + } + optional Utf8Validation utf8_validation = 4 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "NONE"}, + edition_defaults = {edition: EDITION_PROTO3, value: "VERIFY"} + ]; + + enum MessageEncoding { + MESSAGE_ENCODING_UNKNOWN = 0; + LENGTH_PREFIXED = 1; + DELIMITED = 2; + } + optional MessageEncoding message_encoding = 5 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "LENGTH_PREFIXED"} + ]; + + enum JsonFormat { + JSON_FORMAT_UNKNOWN = 0; + ALLOW = 1; + LEGACY_BEST_EFFORT = 2; + } + optional JsonFormat json_format = 6 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_MESSAGE, + targets = TARGET_TYPE_ENUM, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + }, + edition_defaults = {edition: EDITION_PROTO2, value: "LEGACY_BEST_EFFORT"}, + edition_defaults = {edition: EDITION_PROTO3, value: "ALLOW"} + ]; + + reserved 999; + + extensions 1000 to 9994 [ + declaration = { + number: 1000, + full_name: ".pb.cpp", + type: ".pb.CppFeatures" +}, + declaration = { + number: 1001, + full_name: ".pb.java", + type: ".pb.JavaFeatures" +}, + declaration = {number: 1002, full_name: ".pb.go", type: ".pb.GoFeatures"}, + declaration = { + number: 9990, + full_name: ".pb.proto1", + type: ".pb.Proto1Features" +} +]; + + extensions 9995 to 9999; // For internal testing + extensions 10000; // for https://github.com/bufbuild/protobuf-es + } + +// A compiled specification for the defaults of a set of features. These +// messages are generated from FeatureSet extensions and can be used to seed +// feature resolution. The resolution with this object becomes a simple search +// for the closest matching edition, followed by proto merges. +message FeatureSetDefaults { + // A map from every known edition with a unique set of defaults to its + // defaults. Not all editions may be contained here. For a given edition, + // the defaults at the closest matching edition ordered at or before it should + // be used. This field must be in strict ascending order by edition. + message FeatureSetEditionDefault { + optional Edition edition = 3; + + // Defaults of features that can be overridden in this edition. + optional FeatureSet overridable_features = 4; + + // Defaults of features that can't be overridden in this edition. + optional FeatureSet fixed_features = 5; + + reserved 1, 2; + reserved "features"; + } + repeated FeatureSetEditionDefault defaults = 1; + + // The minimum supported edition (inclusive) when this was constructed. + // Editions before this will not have defaults. + optional Edition minimum_edition = 4; + + // The maximum known edition (inclusive) when this was constructed. Editions + // after this will not have reliable defaults. + optional Edition maximum_edition = 5; +} + // =================================================================== // Optional source code info @@ -803,8 +1181,8 @@ message SourceCodeInfo { // location. // // Each element is a field number or an index. They form a path from - // the root FileDescriptorProto to the place where the definition. For - // example, this path: + // the root FileDescriptorProto to the place where the definition appears. + // For example, this path: // [ 4, 3, 2, 7, 1 ] // refers to: // file.message_type(3) // 4, 3 @@ -858,13 +1236,13 @@ message SourceCodeInfo { // // Comment attached to baz. // // Another line attached to baz. // - // // Comment attached to qux. + // // Comment attached to moo. // // - // // Another line attached to qux. - // optional double qux = 4; + // // Another line attached to moo. + // optional double moo = 4; // // // Detached comment for corge. This is not leading or trailing comments - // // to qux or corge because there are blank lines separating it from + // // to moo or corge because there are blank lines separating it from // // both. // // // Detached comment for corge paragraph 2. @@ -904,8 +1282,20 @@ message GeneratedCodeInfo { optional int32 begin = 3; // Identifies the ending offset in bytes in the generated code that - // relates to the identified offset. The end offset should be one past + // relates to the identified object. The end offset should be one past // the last relevant byte (so the length of the text = end - begin). optional int32 end = 4; + + // Represents the identified object's effect on the element in the original + // .proto file. + enum Semantic { + // There is no effect or the effect is indescribable. + NONE = 0; + // The element is set or otherwise mutated. + SET = 1; + // An alias to the element is returned. + ALIAS = 2; + } + optional Semantic semantic = 5; } } diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/duration.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/duration.proto index 584e305b..07fa248f 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/duration.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/duration.proto @@ -32,13 +32,13 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/durationpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "DurationProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // A Duration represents a signed, fixed-length span of time represented // as a count of seconds and fractions of seconds at nanosecond @@ -99,7 +99,6 @@ option objc_class_prefix = "GPB"; // be expressed in JSON format as "3.000000001s", and 3 seconds and 1 // microsecond should be expressed in JSON format as "3.000001s". // -// message Duration { // Signed seconds of the span of time. Must be from -315,576,000,000 // to +315,576,000,000 inclusive. Note: these bounds are computed from: diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/empty.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/empty.proto index 5f992de9..b87c89dc 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/empty.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/empty.proto @@ -32,12 +32,12 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/emptypb"; option java_package = "com.google.protobuf"; option java_outer_classname = "EmptyProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; // A generic empty message that you can re-use to avoid defining duplicated @@ -48,5 +48,4 @@ option cc_enable_arenas = true; // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); // } // -// The JSON representation for `Empty` is empty JSON object `{}`. message Empty {} diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/field_mask.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/field_mask.proto index 66493052..c33a9207 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/field_mask.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/field_mask.proto @@ -32,11 +32,11 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option java_package = "com.google.protobuf"; option java_outer_classname = "FieldMaskProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; option cc_enable_arenas = true; diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/java_features.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/java_features.proto new file mode 100644 index 00000000..d314b886 --- /dev/null +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/java_features.proto @@ -0,0 +1,71 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package pb; + +import "google/protobuf/descriptor.proto"; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "JavaFeaturesProto"; + +extend google.protobuf.FeatureSet { + optional JavaFeatures java = 1001; +} + +message JavaFeatures { + // Whether or not to treat an enum field as closed. This option is only + // applicable to enum fields, and will be removed in the future. It is + // consistent with the legacy behavior of using proto3 enum types for proto2 + // fields. + optional bool legacy_closed_enum = 1 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2023, + deprecation_warning: "The legacy closed enum treatment in Java is " + "deprecated and is scheduled to be removed in " + "edition 2025. Mark enum type on the enum " + "definitions themselves rather than on fields.", + }, + edition_defaults = {edition: EDITION_PROTO2, value: "true"}, + edition_defaults = {edition: EDITION_PROTO3, value: "false"} + ]; + + // The UTF8 validation strategy to use. See go/editions-utf8-validation for + // more information on this feature. + enum Utf8Validation { + // Invalid default, which should never be used. + UTF8_VALIDATION_UNKNOWN = 0; + // Respect the UTF8 validation behavior specified by the global + // utf8_validation feature. + DEFAULT = 1; + // Verifies UTF8 validity overriding the global utf8_validation + // feature. This represents the legacy java_string_check_utf8 option. + VERIFY = 2; + } + optional Utf8Validation utf8_validation = 2 [ + retention = RETENTION_RUNTIME, + targets = TARGET_TYPE_FIELD, + targets = TARGET_TYPE_FILE, + // TODO Enable this in google3 once protoc rolls out. + feature_support = { + edition_introduced: EDITION_2023, + edition_deprecated: EDITION_2023, + deprecation_warning: "The Java-specific utf8 validation feature is " + "deprecated and is scheduled to be removed in " + "edition 2025. Utf8 validation behavior should " + "use the global cross-language utf8_validation " + "feature.", + }, + edition_defaults = {edition: EDITION_PROTO2, value: "DEFAULT"} + ]; +} diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/source_context.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/source_context.proto index 07a0cc35..8d25f486 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/source_context.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/source_context.proto @@ -32,11 +32,11 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option java_package = "com.google.protobuf"; option java_outer_classname = "SourceContextProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; // `SourceContext` represents information about the source of a diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/struct.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/struct.proto index b4fd6357..8cec1e1c 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/struct.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/struct.proto @@ -32,13 +32,13 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/structpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "StructProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // `Struct` represents a structured data value, consisting of fields // which map to dynamically typed values. In some languages, `Struct` @@ -55,8 +55,8 @@ message Struct { // `Value` represents a dynamically typed value which can be either // null, a number, a string, a boolean, a recursive struct value, or a -// list of values. A producer of value is expected to set one of that -// variants, absence of any variant indicates an error. +// list of values. A producer of value is expected to set one of these +// variants. Absence of any variant indicates an error. // // The JSON representation for `Value` is JSON value. message Value { @@ -80,7 +80,7 @@ message Value { // `NullValue` is a singleton enumeration to represent the null value for the // `Value` type union. // -// The JSON representation for `NullValue` is JSON `null`. +// The JSON representation for `NullValue` is JSON `null`. enum NullValue { // Null value. NULL_VALUE = 0; diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/timestamp.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/timestamp.proto index 5b6e50f7..e509315a 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/timestamp.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/timestamp.proto @@ -32,13 +32,13 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/timestamppb"; option java_package = "com.google.protobuf"; option java_outer_classname = "TimestampProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // A Timestamp represents a point in time independent of any time zone or local // calendar, encoded as a count of seconds and fractions of seconds at @@ -90,7 +90,6 @@ option objc_class_prefix = "GPB"; // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) // .setNanos((int) ((millis % 1000) * 1000000)).build(); // -// // Example 5: Compute Timestamp from Java `Instant.now()`. // // Instant now = Instant.now(); @@ -99,7 +98,6 @@ option objc_class_prefix = "GPB"; // Timestamp.newBuilder().setSeconds(now.getEpochSecond()) // .setNanos(now.getNano()).build(); // -// // Example 6: Compute Timestamp from current time in Python. // // timestamp = Timestamp() @@ -129,10 +127,9 @@ option objc_class_prefix = "GPB"; // [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with // the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use // the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D +// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() // ) to obtain a formatter capable of generating timestamps in this format. // -// message Timestamp { // Represents seconds of UTC time since Unix epoch // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/type.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/type.proto index 9f2d457c..1c320ee8 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/type.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/type.proto @@ -35,12 +35,12 @@ package google.protobuf; import "google/protobuf/any.proto"; import "google/protobuf/source_context.proto"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option java_package = "com.google.protobuf"; option java_outer_classname = "TypeProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option go_package = "google.golang.org/protobuf/types/known/typepb"; // A protocol buffer message type. @@ -57,6 +57,8 @@ message Type { SourceContext source_context = 5; // The source syntax. Syntax syntax = 6; + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + string edition = 7; } // A single field of a message type. @@ -151,6 +153,8 @@ message Enum { SourceContext source_context = 4; // The source syntax. Syntax syntax = 5; + // The source edition string, only valid when syntax is SYNTAX_EDITIONS. + string edition = 6; } // Enum value definition. @@ -184,4 +188,6 @@ enum Syntax { SYNTAX_PROTO2 = 0; // Syntax `proto3`. SYNTAX_PROTO3 = 1; + // Syntax `editions`. + SYNTAX_EDITIONS = 2; } diff --git a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/wrappers.proto b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/wrappers.proto index 92b1d1d4..b3ec6cd4 100644 --- a/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/wrappers.proto +++ b/src/main/resources/io/kanro/idea/plugin/protobuf/proto/google/protobuf/wrappers.proto @@ -27,7 +27,7 @@ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - +// // Wrappers for primitive (non-message) types. These types are useful // for embedding primitives in the `google.protobuf.Any` type and for places // where we need to distinguish between the absence of a primitive @@ -42,13 +42,13 @@ syntax = "proto3"; package google.protobuf; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; option java_package = "com.google.protobuf"; option java_outer_classname = "WrappersProto"; option java_multiple_files = true; option objc_class_prefix = "GPB"; +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; // Wrapper message for `double`. //