Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

telemetry(amazonq): AI code gen % for Q features #5215

Merged
merged 40 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6b0c457
reduce frequency of system information polling
leigaol Dec 11, 2024
8ec2360
Merge branch 'main' of github.com:leigaol/aws-toolkit-jetbrains
leigaol Dec 17, 2024
892c494
Merge branch 'main' of github.com:leigaol/aws-toolkit-jetbrains
leigaol Dec 18, 2024
47fadd3
init commit of ai code gen %
leigaol Dec 19, 2024
b0b5e3a
more code
leigaol Dec 19, 2024
c1f3716
update
leigaol Dec 20, 2024
6f5a1ca
use topic event
leigaol Dec 26, 2024
5d44be9
listen to all q editor edits
leigaol Dec 26, 2024
3cc36c5
add event whenever Q feature is used
leigaol Dec 26, 2024
72a6a84
Merge branch 'main' into ai_gen
leigaol Dec 26, 2024
04a7dce
fix build error
leigaol Dec 27, 2024
8cd9eda
add unit test
leigaol Dec 27, 2024
3e05e4a
adjust
leigaol Dec 27, 2024
c8b29fe
update if else cond
leigaol Dec 27, 2024
05b2ced
Merge branch 'main' into ai_gen
leigaol Jan 6, 2025
b2a60fd
fix detekt
leigaol Jan 6, 2025
25fa105
:plugin-amazonq:chat:jetbrains-community:detekt fix
leigaol Jan 6, 2025
3c9861a
Merge branch 'main' into ai_gen
leigaol Jan 8, 2025
8edc6cd
Merge branch 'main' into ai_gen
leigaol Jan 8, 2025
aae3cba
Merge branch 'main' into ai_gen
leigaol Jan 9, 2025
89a27ca
merge
leigaol Jan 13, 2025
40aba30
Merge branch 'main' into ai_gen
leigaol Jan 14, 2025
1c5ad05
Merge branch 'main' into ai_gen
leigaol Jan 15, 2025
f3200a4
Merge branch 'main' into ai_gen
leigaol Jan 16, 2025
388ac7c
Merge branch 'main' into ai_gen
leigaol Jan 17, 2025
9c608ec
Merge branch 'main' into ai_gen
leigaol Jan 21, 2025
3a8c24f
resolve some feedback comments
leigaol Jan 21, 2025
937e53d
revise unit test
leigaol Jan 21, 2025
d359a84
add read access assert
leigaol Jan 21, 2025
5461187
Merge branch 'main' into ai_gen
leigaol Jan 21, 2025
82cba18
fix detekt
leigaol Jan 21, 2025
8203f38
Merge branch 'ai_gen' of github.com:leigaol/aws-toolkit-jetbrains int…
leigaol Jan 21, 2025
8302eb0
Merge branch 'main' into ai_gen
leigaol Jan 21, 2025
79631b2
fix import error
leigaol Jan 21, 2025
35dc2e7
fix detekt
leigaol Jan 21, 2025
067ef16
Merge branch 'main' into ai_gen
leigaol Jan 21, 2025
5a9f201
Merge branch 'main' into ai_gen
leigaol Jan 21, 2025
6ec3f7c
fix unit test
leigaol Jan 21, 2025
2a73168
add RequireReadlock
leigaol Jan 21, 2025
d33534e
Merge branch 'main' into ai_gen
leigaol Jan 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import software.aws.toolkits.jetbrains.services.amazonqCodeScan.messages.CodeSca
import software.aws.toolkits.jetbrains.services.amazonqCodeScan.messages.CodeScanChatMessageContent
import software.aws.toolkits.jetbrains.services.amazonqCodeScan.messages.UpdatePlaceholderMessage
import software.aws.toolkits.jetbrains.services.amazonqCodeScan.storage.ChatSessionStorage
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType
import java.util.UUID

Expand All @@ -34,7 +36,7 @@ class CodeScanChatHelper(
clearPreviousItemButtons: Boolean? = false,
) {
if (isInValidSession()) return

broadcastQEvent(QFeatureEvent.INVOCATION)
messagePublisher.publish(
CodeScanChatMessage(
tabId = activeCodeScanTabId as String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendA
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor
import software.aws.toolkits.jetbrains.services.codewhisperer.language.CodeWhispererProgrammingLanguage
import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmingLanguage
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.toolwindow.CodeWhispererCodeReferenceManager
import software.aws.toolkits.jetbrains.services.codewhisperer.util.isWithin
import software.aws.toolkits.jetbrains.services.cwc.ChatConstants
Expand Down Expand Up @@ -1205,6 +1207,7 @@ class CodeTestChatController(
"Processing message: $message " +
"tabId: $tabId"
}
broadcastQEvent(QFeatureEvent.INVOCATION)
when (session.conversationState) {
ConversationState.WAITING_FOR_BUILD_COMMAND_INPUT -> handleBuildCommandInput(session, message)
ConversationState.WAITING_FOR_REGENERATE_INPUT -> handleRegenerateInput(session, message)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Delete
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.NewFileZipInfo
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.SessionStatePhase
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.CancellationTokenSource
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.resources.message
import java.nio.file.Paths
import java.util.UUID
Expand Down Expand Up @@ -718,6 +720,7 @@ class DocController(
is PrepareDocGenerationState -> state.filePaths
else -> emptyList()
}
broadcastQEvent(QFeatureEvent.INVOCATION)

if (filePaths.isNotEmpty()) {
processOpenDiff(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Sessio
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.storage.ChatSessionStorage
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.InsertAction
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.getFollowUpOptions
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.util.content
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.FeedbackComment
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
Expand Down Expand Up @@ -191,6 +193,7 @@ class FeatureDevController(
logger.debug { "$FEATURE_NAME: Processing InsertCodeAtCursorPosition: $message" }

withContext(EDT) {
broadcastQEvent(QFeatureEvent.STARTS_EDITING)
val editor: Editor = FileEditorManager.getInstance(context.project).selectedTextEditor ?: return@withContext

val caret: Caret = editor.caretModel.primaryCaret
Expand All @@ -202,6 +205,7 @@ class FeatureDevController(
}
editor.document.insertString(offset, message.code)
}
broadcastQEvent(QFeatureEvent.FINISHES_EDITING)
}
}

Expand Down Expand Up @@ -679,7 +683,7 @@ class FeatureDevController(
}

session.preloader(message, messenger)

broadcastQEvent(QFeatureEvent.INVOCATION)
when (session.sessionState.phase) {
SessionStatePhase.CODEGEN -> onCodeGeneration(session, message, tabId)
else -> null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ import software.aws.toolkits.jetbrains.services.amazonq.project.ProjectContextCo
import software.aws.toolkits.jetbrains.services.amazonq.project.RelevantDocument
import software.aws.toolkits.jetbrains.services.codewhisperer.settings.CodeWhispererConfigurable
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererUserModificationTracker
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.cwc.InboundAppMessagesHandler
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.exceptions.ChatApiException
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.ChatRequestData
Expand Down Expand Up @@ -215,6 +217,7 @@ class ChatController private constructor(
}

override suspend fun processInsertCodeAtCursorPosition(message: IncomingCwcMessage.InsertCodeAtCursorPosition) {
broadcastQEvent(QFeatureEvent.STARTS_EDITING)
withContext(EDT) {
val editor: Editor = FileEditorManager.getInstance(context.project).selectedTextEditor ?: return@withContext

Expand Down Expand Up @@ -245,6 +248,8 @@ class ChatController private constructor(
}
}
telemetryHelper.recordInteractWithMessage(message)

broadcastQEvent(QFeatureEvent.FINISHES_EDITING)
}

override suspend fun processStopResponseMessage(message: IncomingCwcMessage.StopResponse) {
Expand Down Expand Up @@ -438,7 +443,7 @@ class ChatController private constructor(
sessionInfo.history.add(requestData)
telemetryHelper.recordEnterFocusConversation(tabId)
telemetryHelper.recordStartConversation(tabId, requestData)

broadcastQEvent(QFeatureEvent.INVOCATION)
// Send the request to the API and publish the responses back to the UI.
// This is launched in a scope attached to the sessionInfo so that the Job can be cancelled on a per-session basis.
ChatPromptHandler(telemetryHelper).handle(tabId, triggerId, requestData, sessionInfo, shouldAddIndexInProgressMessage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import software.amazon.awssdk.awscore.exception.AwsServiceException
import software.amazon.awssdk.services.codewhispererstreaming.model.CodeWhispererStreamingException
import software.aws.toolkits.core.utils.convertMarkdownToHTML
import software.aws.toolkits.core.utils.extractCodeBlockLanguage
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.exceptions.ChatApiException
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.ChatRequestData
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.ChatResponseEvent
Expand Down Expand Up @@ -115,6 +117,8 @@ class ChatPromptHandler(private val telemetryHelper: TelemetryHelper) {
)
telemetryHelper.recordAddMessage(data, response, responseText.length, statusCode, countTotalNumberOfCodeBlocks(responseText))
emit(response)

broadcastQEvent(QFeatureEvent.INVOCATION)
}
.catch { exception ->
val statusCode = if (exception is AwsServiceException) exception.statusCode() else 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ import software.aws.toolkits.jetbrains.services.amazonq.auth.AuthController
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AMAZON_Q_WINDOW_ID
import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererModelConfigurator
import software.aws.toolkits.jetbrains.services.codewhisperer.model.CaretPosition
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.ChatRequestData
import software.aws.toolkits.jetbrains.services.cwc.clients.chat.model.TriggerType
import software.aws.toolkits.jetbrains.services.cwc.controller.ReferenceLogController
Expand Down Expand Up @@ -191,7 +193,6 @@ class InlineChatController(

private fun addPopupListeners(popup: JBPopup, editor: Editor) {
val popupListener = object : JBPopupListener {

override fun onClosed(event: LightweightWindowEvent) {
if (canPopupAbort.get() && event.asPopup().isDisposed) {
popupCancelHandler.invoke(editor)
Expand Down Expand Up @@ -534,6 +535,7 @@ class InlineChatController(
private fun insertString(editor: Editor, offset: Int, text: String): RangeMarker {
lateinit var rangeMarker: RangeMarker

broadcastQEvent(QFeatureEvent.STARTS_EDITING)
ApplicationManager.getApplication().invokeAndWait {
CommandProcessor.getInstance().runUndoTransparentAction {
WriteCommandAction.runWriteCommandAction(project) {
Expand All @@ -543,18 +545,20 @@ class InlineChatController(
highlightCodeWithBackgroundColor(editor, rangeMarker.startOffset, rangeMarker.endOffset, true)
}
}

broadcastQEvent(QFeatureEvent.FINISHES_EDITING)
return rangeMarker
}

private fun replaceString(document: Document, start: Int, end: Int, text: String) {
broadcastQEvent(QFeatureEvent.STARTS_EDITING)
ApplicationManager.getApplication().invokeAndWait {
CommandProcessor.getInstance().runUndoTransparentAction {
WriteCommandAction.runWriteCommandAction(project) {
document.replaceString(start, end, text)
}
}
}
broadcastQEvent(QFeatureEvent.FINISHES_EDITING)
}

private fun highlightString(editor: Editor, start: Int, end: Int, isInsert: Boolean) {
Expand Down Expand Up @@ -711,6 +715,8 @@ class InlineChatController(
canPopupAbort.set(true)
undoChanges()
}

broadcastQEvent(QFeatureEvent.FINISHES_EDITING)
return errorMessage
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ import software.aws.toolkits.jetbrains.services.codemodernizer.utils.toVirtualFi
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.tryGetJdk
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.unzipFile
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.validateSctMetadata
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType
import software.aws.toolkits.resources.message

Expand All @@ -136,7 +138,7 @@ class CodeTransformChatController(
if (objective == "language upgrade" || objective == "sql conversion") {
telemetry.submitSelection(objective)
}

broadcastQEvent(QFeatureEvent.INVOCATION)
when (objective) {
"language upgrade" -> this.handleLanguageUpgrade()
"sql conversion" -> this.handleSQLConversion()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhisp
import software.aws.toolkits.jetbrains.services.codewhisperer.language.CodeWhispererProgrammingLanguage
import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmingLanguage
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.toolwindow.CodeWhispererCodeReferenceManager
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.CODE_SCAN_ISSUE_TITLE_MAX_LENGTH
Expand Down Expand Up @@ -331,6 +333,7 @@ fun applySuggestedFix(project: Project, issue: CodeWhispererCodeScanIssue) {
try {
val manager = CodeWhispererCodeReferenceManager.getInstance(issue.project)
WriteCommandAction.runWriteCommandAction(issue.project) {
broadcastQEvent(QFeatureEvent.STARTS_EDITING)
val document = FileDocumentManager.getInstance().getDocument(issue.file) ?: return@runWriteCommandAction

val documentContent = document.text
Expand All @@ -343,6 +346,7 @@ fun applySuggestedFix(project: Project, issue: CodeWhispererCodeScanIssue) {
LOG.debug { "Original content from reference span: $originalContent" }
manager.addReferenceLogPanelEntry(reference = reference, null, null, originalContent.split("\n"))
}
broadcastQEvent(QFeatureEvent.FINISHES_EDITING)
}
if (issue.suggestedFixes[0].references.isNotEmpty()) {
manager.toolWindow?.show()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ interface CodeWhispererClientAdaptor : Disposable {
acceptedTokenCount: Long,
totalTokenCount: Long,
unmodifiedAcceptedTokenCount: Long?,
userWrittenCodeCharacterCount: Long?,
userWrittenCodeLineCount: Long?,
): SendTelemetryEventResponse

fun sendUserModificationTelemetry(
Expand Down Expand Up @@ -481,6 +483,8 @@ open class CodeWhispererClientAdaptorImpl(override val project: Project) : CodeW
acceptedTokenCount: Long,
totalTokenCount: Long,
unmodifiedAcceptedTokenCount: Long?,
userWrittenCodeCharacterCount: Long?,
userWrittenCodeLineCount: Long?,
): SendTelemetryEventResponse = bearerClient().sendTelemetryEvent { requestBuilder ->
requestBuilder.telemetryEvent { telemetryEventBuilder ->
telemetryEventBuilder.codeCoverageEvent {
Expand All @@ -490,6 +494,8 @@ open class CodeWhispererClientAdaptorImpl(override val project: Project) : CodeW
it.totalCharacterCount(totalTokenCount.toInt())
it.timestamp(Instant.now())
it.unmodifiedAcceptedCharacterCount(unmodifiedAcceptedTokenCount?.toInt())
it.userWrittenCodeCharacterCount(userWrittenCodeLineCount?.toInt())
it.userWrittenCodeLineCount(userWrittenCodeLineCount?.toInt())
}
}
requestBuilder.optOutPreference(getTelemetryOptOutPreference())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmi
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatusNew
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererCodeCoverageTracker
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.UserWrittenCodeTracker

class CodeWhispererEditorListener : EditorFactoryListener {
override fun editorCreated(event: EditorFactoryEvent) {
Expand All @@ -40,6 +41,10 @@ class CodeWhispererEditorListener : EditorFactoryListener {
activateTrackerIfNotActive()
documentChanged(event)
}
UserWrittenCodeTracker.getInstance(project).apply {
activateTrackerIfNotActive()
documentChanged(event)
}
}
},
editor.disposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.model.InvocationCo
import software.aws.toolkits.jetbrains.services.codewhisperer.model.SessionContext
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.CodeWhispererPopupManager
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CaretMovement
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.PAIRED_BRACKETS
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.PAIRED_QUOTES
Expand Down Expand Up @@ -44,9 +46,12 @@ class CodeWhispererEditorManager {
val endOffsetToReplace = if (insertEndOffset != -1) insertEndOffset else primaryCaret.offset

WriteCommandAction.runWriteCommandAction(project) {
broadcastQEvent(QFeatureEvent.STARTS_EDITING)
document.replaceString(originalOffset, endOffsetToReplace, reformatted)
PsiDocumentManager.getInstance(project).commitDocument(document)
primaryCaret.moveToOffset(endOffset + detail.rightOverlap.length)

broadcastQEvent(QFeatureEvent.FINISHES_EDITING)
}

ApplicationManager.getApplication().invokeLater {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.popup.CodeWhispere
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.CodeWhispererPopupManagerNew
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererServiceNew
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryServiceNew
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.QFeatureEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.broadcastQEvent
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CaretMovement
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.PAIRED_BRACKETS
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.PAIRED_QUOTES
Expand Down Expand Up @@ -51,9 +53,12 @@ class CodeWhispererEditorManagerNew {
preview.detail.isAccepted = true

WriteCommandAction.runWriteCommandAction(project) {
broadcastQEvent(QFeatureEvent.STARTS_EDITING)
document.replaceString(originalOffset, endOffsetToReplace, reformatted)
PsiDocumentManager.getInstance(project).commitDocument(document)
primaryCaret.moveToOffset(endOffset + detail.rightOverlap.length)

broadcastQEvent(QFeatureEvent.FINISHES_EDITING)
}

ApplicationManager.getApplication().invokeLater {
Expand Down
Loading
Loading