Skip to content

Commit

Permalink
Merge pull request #26 from dinbtechit/feature/4-live-templates
Browse files Browse the repository at this point in the history
Feature/4 live templates
  • Loading branch information
dinbtechit committed Oct 7, 2023
2 parents bff7e76 + e68a411 commit 9a107a1
Show file tree
Hide file tree
Showing 49 changed files with 1,526 additions and 129 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
# ngxs Changelog

## [Unreleased]
### Added
- #4 - NGXS Live templates

### Fixed
- Moved all the deprecated APIs to latest ones.

## [0.0.5] - 2023-09-19

Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@
](https://www.buymeacoffee.com/dinbtechit)

<!-- Plugin description -->
NGXS is a state management library for Angular. This plugin provides NGXS CLI/Schematics for Jetbrains IDE.
NGXS is a state management library for Angular. This plugin provides NGXS CLI/Schematics, Intellisense and
auto-completions for Jetbrains IDE.

> Please ensure you have [ngxs cli](https://www.ngxs.io/plugins/cli) installed either globally or at the project level.
# Features

- Simply right click -> New -> NGXS CLI/Schematics to generate a boiler plate store.
- Navigate to Action Implementation using Gutter Icons
- Navigate to Action Implementation using Gutter Icons
- LiveTemplate to autocompletion for creating `@Actions`, `@Selectors` and `export class NewActions` quickly
- `cmd`+ `Insert`/`ctrl`+ `Insert` within Generator
- `Alt` + 'Enter' / `options` + `Enter` - QuickFixes and generate @Actions & @Selectors quickly
- Many more coming soon. Checkout roadmap

# Roadmap

- [ ] NPM install ngxs package when does not exist
- [ ] Live Templates

<!-- Plugin description end -->

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pluginGroup = com.github.dinbtechit.ngxs
pluginName = ngxs
pluginRepositoryUrl = https://github.com/dinbtechit/ngxs
# SemVer format -> https://semver.org
pluginVersion = 0.0.5
pluginVersion = 0.0.6

# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild = 223
Expand Down
5 changes: 5 additions & 0 deletions src/main/kotlin/com/github/dinbtechit/ngxs/NgxsIcons.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ object NgxsIcons {
val Action = IconLoader.getIcon("icons/ngxs-action.svg", javaClass)
val MultipleActions = IconLoader.getIcon("icons/ngxs-multiple-action.svg", javaClass)
}
object Editor {
@JvmField
//val Completion = IconLoader.getIcon("icons/ngxs.svg", javaClass)
val Completion = IconLoader.getIcon("icons/ngxs-completion-icon.svg", javaClass)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.dinbtechit.ngxs.action.editor.codeIntellisense
package com.github.dinbtechit.ngxs.action.editor.codeIntellisense.annotator

import com.github.dinbtechit.ngxs.action.editor.NgxsActionUtil
import com.github.dinbtechit.ngxs.action.editor.codeIntellisense.inspection.quickfix.NgxsCreateActionQuickFix
import com.github.dinbtechit.ngxs.action.editor.psi.actions.NgxsActionsPsiUtil
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
Expand Down Expand Up @@ -28,11 +29,11 @@ class NgxsAnnotator : Annotator {
var actionFileName: String? = null
var actionVirtualFile: VirtualFile? = null

if (NgxsActionUtil.isActionClass(element)) {
isImplementationExist = NgxsActionUtil.isActionImplExist(element)
if (NgxsActionsPsiUtil.isActionClass(element)) {
isImplementationExist = NgxsActionsPsiUtil.isActionImplExist(element)
problemType = ProblemHighlightType.LIKE_UNUSED_SYMBOL
try {
val classNamePsiElement = NgxsActionUtil.getActionClassPsiElement(element)
val classNamePsiElement = NgxsActionsPsiUtil.getActionClassPsiElement(element)
if (classNamePsiElement != null) {
range = TextRange(classNamePsiElement.startOffset, classNamePsiElement.endOffset)
actionPsiClass = classNamePsiElement
Expand All @@ -44,11 +45,11 @@ class NgxsAnnotator : Annotator {
throw Exception("NgxsAnnotator - Unable to establish range for the ActionClass - ${element.text}")
}

} else if (NgxsActionUtil.isActionDispatched(element)) {
isImplementationExist = NgxsActionUtil.isActionImplExist(element)
} else if (NgxsActionsPsiUtil.isActionDispatched(element)) {
isImplementationExist = NgxsActionsPsiUtil.isActionImplExist(element)
val refElement = element.parent.reference?.resolve()
if (refElement != null) {
val classNamePsiElement = NgxsActionUtil.getActionClassPsiElement(refElement)
val classNamePsiElement = NgxsActionsPsiUtil.getActionClassPsiElement(refElement)
if (classNamePsiElement != null) {
actionName = classNamePsiElement.text
actionPsiClass = classNamePsiElement
Expand Down Expand Up @@ -83,10 +84,10 @@ class NgxsAnnotator : Annotator {
.highlightType(problemType)
.withFix(
NgxsCreateActionQuickFix("Create @Action(${actionName}) in $stateFileName.",
actionPsiClass!!, stateFile))
actionPsiClass!!, stateFile)
)
.create()
}

}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.github.dinbtechit.ngxs.action.editor.codeIntellisense.completion

import com.github.dinbtechit.ngxs.action.editor.codeIntellisense.completion.providers.NgxsActionsFileCompletionProvider
import com.github.dinbtechit.ngxs.action.editor.codeIntellisense.completion.providers.NgxsStateFileCompletionProvider
import com.intellij.codeInsight.completion.CompletionContributor
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.patterns.PlatformPatterns.psiElement
import com.intellij.psi.PsiFile

data class NgxsLiveTemplates(
val presentableText: String,
val tailText: String? = null,
val lookUpStrings: List<String>,
val generateTemplate: () -> Unit
)

class NgxsCompletionContributor : CompletionContributor() {
init {
extend(CompletionType.BASIC,
psiElement().inside(psiElement(PsiFile::class.java)),
NgxsActionsFileCompletionProvider()
)
extend(CompletionType.BASIC,
psiElement().inside(psiElement(PsiFile::class.java)),
NgxsStateFileCompletionProvider()
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.github.dinbtechit.ngxs.action.editor.codeIntellisense.completion.helpers

import com.intellij.codeInsight.completion.InsertionContext
import com.intellij.openapi.util.TextRange

fun InsertionContext.trimStartAtCurrentCaretPosition() {
val lineStartOffset = document.getLineStartOffset(editor.caretModel.logicalPosition.line)
val lineEndOffset = document.getLineEndOffset(editor.caretModel.logicalPosition.line)
var text = document.getText(TextRange(lineStartOffset, lineEndOffset))
text = text.replaceFirst(text.trim(), "")
document.replaceString(
lineStartOffset,
lineEndOffset, text
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.github.dinbtechit.ngxs.action.editor.codeIntellisense.completion.providers

import com.github.dinbtechit.ngxs.NgxsIcons
import com.github.dinbtechit.ngxs.action.editor.codeIntellisense.completion.NgxsLiveTemplates
import com.github.dinbtechit.ngxs.action.editor.codeIntellisense.completion.helpers.trimStartAtCurrentCaretPosition
import com.github.dinbtechit.ngxs.action.editor.psi.actions.NgxsActionsPsiFileFactory
import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionProvider
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.AutoCompletionPolicy
import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import com.intellij.util.ProcessingContext

class NgxsActionsFileCompletionProvider : CompletionProvider<CompletionParameters>() {
override fun addCompletions(
parameters: CompletionParameters,
context: ProcessingContext,
resultSet: CompletionResultSet
) {
val position = parameters.position
val file = position.containingFile
if (file.name.contains(".actions.ts")) {
addCompletions(parameters, resultSet)
}
}

private fun addCompletions(parameters: CompletionParameters, resultSet: CompletionResultSet) {
getResultSets(parameters).forEach {
resultSet.addElement(
LookupElementBuilder.create(it.value.presentableText.replaceTextExist(parameters.editor))
.withIcon(NgxsIcons.Editor.Completion)
.withPresentableText(it.value.presentableText.replaceTextExist(parameters.editor))
.withTailText(it.value.tailText)
.withTypeText("NGXS")
.withLookupStrings(it.value.lookUpStrings)
.withCaseSensitivity(false)
.withInsertHandler { context, _ ->
context.trimStartAtCurrentCaretPosition()
it.value.generateTemplate()
}
.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE)
)
}
}

private fun getResultSets(parameters: CompletionParameters): Map<String, NgxsLiveTemplates> {
return mapOf(
// 1. CreateAction
"createAction" to NgxsLiveTemplates(
presentableText = "export class NewAction",
tailText = "(){...}",
lookUpStrings = listOf(
"export class NewAction",
"action-definition",
"ngxs-action-definition"
),
generateTemplate = {
NgxsActionsPsiFileFactory.createActionDeclarationFromActionFile(
parameters.originalFile, addNewLine = false
)
}
),
// 2. CreateActionWithPayload
"createActionWithPayload" to NgxsLiveTemplates(
presentableText = "export class NewAction-with-payload",
tailText = "(){...}",
lookUpStrings = listOf(
"export class NewAction",
"action-definition",
"ngxs-action-definition-with-payload"
),
generateTemplate = {
NgxsActionsPsiFileFactory.createActionDeclarationFromActionFile(
parameters.originalFile, withPayload = true, addNewLine = false
)
}
),
)
}

private fun String.replaceTextExist(editor:Editor): String {
val lineStartOffset = editor.document.getLineStartOffset(editor.caretModel.logicalPosition.line)
val lineEndOffset = editor.document.getLineEndOffset(editor.caretModel.logicalPosition.line)
val text = editor.document.getText(TextRange(lineStartOffset, lineEndOffset))
val tokens = text.split(" ")
var newText = this
for(token in tokens) {
newText = newText.replace("\\b$token\\b".toRegex(), "")
}
return newText.trim()
}

}



Loading

0 comments on commit 9a107a1

Please sign in to comment.