Skip to content

Commit d177f1d

Browse files
committed
remanme package and get ready to commit
1 parent 462067e commit d177f1d

155 files changed

Lines changed: 29026 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// SPDX-FileCopyrightText: 2025 Weibo, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.zoocode.jetbrains.actions
6+
7+
import com.intellij.openapi.actionSystem.AnAction
8+
import com.intellij.openapi.actionSystem.AnActionEvent
9+
import com.intellij.openapi.diagnostic.Logger
10+
import com.intellij.openapi.project.Project
11+
12+
/**
13+
* Executes a VSCode command with the given command ID.
14+
* This function uses the RPC protocol to communicate with the extension host.
15+
*
16+
* @param commandId The identifier of the command to execute
17+
* @param project The current project context
18+
*/
19+
fun executeCommand(commandId: String, project: Project?, vararg args: Any?, hasArgs: Boolean? = true) {
20+
val logger = com.intellij.openapi.diagnostic.Logger.getInstance("VSCodeCommandActions")
21+
logger.info("🔍 executeCommand called with commandId: $commandId")
22+
23+
if (project == null) {
24+
logger.warn("❌ Project is null, cannot execute command")
25+
return
26+
}
27+
28+
try {
29+
val pluginContext = project.getService(org.zoocode.jetbrains.core.PluginContext::class.java)
30+
if (pluginContext == null) {
31+
logger.warn("❌ PluginContext not found")
32+
return
33+
}
34+
35+
val rpcProtocol = pluginContext.getRPCProtocol()
36+
if (rpcProtocol == null) {
37+
logger.warn("❌ RPC Protocol not found")
38+
return
39+
}
40+
41+
val proxy = rpcProtocol.getProxy(org.zoocode.jetbrains.core.ServiceProxyRegistry.ExtHostContext.ExtHostCommands)
42+
if (proxy == null) {
43+
logger.warn("❌ ExtHostCommands proxy not found")
44+
return
45+
}
46+
47+
logger.info("🔍 Executing command via RPC: $commandId, argsCount=${args.size}")
48+
if (hasArgs == true) {
49+
proxy.executeContributedCommand(commandId, args)
50+
} else {
51+
proxy.executeContributedCommand(commandId)
52+
}
53+
54+
logger.info("✅ Command sent to Extension Host: $commandId")
55+
56+
} catch (e: Exception) {
57+
logger.error("❌ Error executing command: $commandId", e)
58+
}
59+
}
60+
61+
/**
62+
* Action that opens developer tools for the WebView.
63+
* Takes a function that provides the current WebView instance.
64+
*
65+
* @property getWebViewInstance Function that returns the current WebView instance or null if not available
66+
*/
67+
class OpenDevToolsAction(private val getWebViewInstance: () -> org.zoocode.jetbrains.webview.WebViewInstance?) :
68+
AnAction("Open Developer Tools") {
69+
private val logger: Logger = Logger.getInstance(OpenDevToolsAction::class.java)
70+
71+
/**
72+
* Performs the action to open developer tools for the WebView.
73+
*
74+
* @param e The action event containing context information
75+
*/
76+
override fun actionPerformed(e: AnActionEvent) {
77+
val webView = getWebViewInstance()
78+
if (webView != null) {
79+
webView.openDevTools()
80+
} else {
81+
logger.warn("No WebView instance available, cannot open developer tools")
82+
}
83+
}
84+
}
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// SPDX-FileCopyrightText: 2025 Weibo, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.zoocode.jetbrains.actors
6+
7+
import com.intellij.openapi.application.ApplicationManager
8+
import com.intellij.openapi.diagnostic.Logger
9+
import com.intellij.openapi.project.Project
10+
import com.intellij.openapi.vfs.LocalFileSystem
11+
import org.zoocode.jetbrains.editor.EditorAndDocManager
12+
import org.zoocode.jetbrains.editor.EditorHolder
13+
import org.zoocode.jetbrains.editor.WorkspaceEdit
14+
import org.zoocode.jetbrains.ipc.proxy.SerializableObjectWithBuffers
15+
import kotlinx.coroutines.delay
16+
import java.io.File
17+
import java.nio.file.Files
18+
/**
19+
* Interface for handling bulk edits in the main thread.
20+
* Provides functionality to apply workspace edits that may include multiple file and text changes.
21+
*/
22+
interface MainThreadBulkEditsShape {
23+
/**
24+
* Attempts to apply a workspace edit.
25+
*
26+
* @param workspaceEditDto The workspace edit data transfer object
27+
* @param undoRedoGroupId Optional ID for grouping undo/redo operations
28+
* @param respectAutoSaveConfig Whether to respect auto-save configuration
29+
* @return True if all edits were applied successfully, false otherwise
30+
*/
31+
suspend fun tryApplyWorkspaceEdit(workspaceEditDto: SerializableObjectWithBuffers<Any>, undoRedoGroupId: Int?, respectAutoSaveConfig: Boolean?): Boolean
32+
}
33+
34+
/**
35+
* Implementation of MainThreadBulkEditsShape that handles bulk edits in the main thread.
36+
* Processes workspace edits including file operations (create, delete, rename) and text edits.
37+
*
38+
* @property project The current project context
39+
*/
40+
class MainThreadBulkEdits(val project: Project) : MainThreadBulkEditsShape {
41+
val logger = Logger.getInstance(MainThreadBulkEditsShape::class.java)
42+
43+
/**
44+
* Attempts to apply a workspace edit by processing file operations and text edits.
45+
*
46+
* @param workspaceEditDto The workspace edit data transfer object
47+
* @param undoRedoGroupId Optional ID for grouping undo/redo operations
48+
* @param respectAutoSaveConfig Whether to respect auto-save configuration
49+
* @return True if all edits were applied successfully, false otherwise
50+
*/
51+
override suspend fun tryApplyWorkspaceEdit(workspaceEditDto: SerializableObjectWithBuffers<Any>, undoRedoGroupId: Int?, respectAutoSaveConfig: Boolean?): Boolean {
52+
val json = workspaceEditDto.value as String
53+
logger.info("[Bulk Edit] Starting process: $json")
54+
val cto = WorkspaceEdit.from(json)
55+
var allSuccess = true
56+
57+
// Process file edits - using background thread to avoid EDT violations
58+
cto.files.forEach { fileEdit ->
59+
if (fileEdit.oldResource != null && fileEdit.newResource != null) {
60+
val oldResource = File(fileEdit.oldResource.path)
61+
val newResource = File(fileEdit.newResource.path)
62+
try {
63+
Files.move(oldResource.toPath(), newResource.toPath())
64+
// Move VFS refresh operations to background thread
65+
ApplicationManager.getApplication().executeOnPooledThread {
66+
val vfs = LocalFileSystem.getInstance()
67+
vfs.refreshIoFiles(listOf(oldResource, newResource))
68+
}
69+
logger.info("[Bulk Edit] Renamed file: ${oldResource.path} -> ${newResource.path}")
70+
} catch (e: Exception) {
71+
logger.error("[Bulk Edit] Failed to rename file: ${oldResource.path} -> ${newResource.path}", e)
72+
allSuccess = false
73+
}
74+
} else if (fileEdit.oldResource != null) {
75+
val oldResource = File(fileEdit.oldResource.path)
76+
try {
77+
oldResource.delete()
78+
// Move VFS refresh operations to background thread
79+
ApplicationManager.getApplication().executeOnPooledThread {
80+
val vfs = LocalFileSystem.getInstance()
81+
vfs.refreshIoFiles(listOf(oldResource.parentFile))
82+
}
83+
logger.info("[Bulk Edit] Deleted file: ${oldResource.path}")
84+
} catch (e: Exception) {
85+
logger.error("[Bulk Edit] Failed to delete file: ${oldResource.path}", e)
86+
allSuccess = false
87+
}
88+
} else if (fileEdit.newResource != null) {
89+
val newResource = File(fileEdit.newResource.path)
90+
try {
91+
val parentDir = newResource.parentFile
92+
if (!parentDir.exists()) {
93+
parentDir.mkdirs()
94+
}
95+
if (fileEdit.options?.contents != null) {
96+
Files.write(newResource.toPath(), fileEdit.options!!.contents!!.toByteArray(Charsets.UTF_8))
97+
} else {
98+
newResource.createNewFile()
99+
}
100+
// Move VFS refresh operations to background thread
101+
ApplicationManager.getApplication().executeOnPooledThread {
102+
val vfs = LocalFileSystem.getInstance()
103+
vfs.refreshIoFiles(listOf(newResource))
104+
}
105+
logger.info("[Bulk Edit] Created file: ${newResource.path}")
106+
} catch (e: Exception) {
107+
logger.error("[Bulk Edit] Failed to create file: ${newResource.path}", e)
108+
allSuccess = false
109+
}
110+
}
111+
}
112+
// Process text edits
113+
cto.texts.forEach { textEdit ->
114+
logger.info("[Bulk Edit] Processing text edit: ${textEdit.resource.path}")
115+
if (textEdit.resource.scheme != "file") {
116+
logger.error("[Bulk Edit] Non-file resources not supported: ${textEdit.resource.path}")
117+
allSuccess = false
118+
return@forEach
119+
}
120+
121+
var handle:EditorHolder? = null;
122+
try {
123+
handle = project.getService(EditorAndDocManager::class.java).getEditorHandleByUri(textEdit.resource,true)
124+
if (handle == null) {
125+
handle = project.getService(EditorAndDocManager::class.java).sync2ExtHost(textEdit.resource,true)
126+
}
127+
} catch (e: Exception) {
128+
logger.info("[Bulk Edit] Failed to get editor handle: ${textEdit.resource.path}", e)
129+
}
130+
131+
if (handle == null) {
132+
logger.info("[Bulk Edit] Editor handle not found: ${textEdit.resource.path}")
133+
allSuccess = false
134+
return@forEach
135+
}
136+
137+
try {
138+
val result = handle.applyEdit(textEdit)
139+
if (!result) {
140+
logger.info("[Bulk Edit] Failed to apply edit: ${textEdit.resource.path}")
141+
allSuccess = false
142+
} else {
143+
logger.info("[Bulk Edit] Successfully updated file: ${textEdit.resource.path}")
144+
}
145+
} catch (e: Exception) {
146+
logger.error("[Bulk Edit] Exception applying edit: ${textEdit.resource.path}", e)
147+
allSuccess = false
148+
}
149+
}
150+
return allSuccess
151+
}
152+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// SPDX-FileCopyrightText: 2025 Weibo, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package org.zoocode.jetbrains.actors
6+
7+
import com.intellij.openapi.Disposable
8+
import com.intellij.openapi.diagnostic.Logger
9+
import java.awt.Toolkit
10+
import java.awt.datatransfer.DataFlavor
11+
import java.awt.datatransfer.StringSelection
12+
13+
/**
14+
* Main thread clipboard interface.
15+
* Corresponds to the MainThreadClipboardShape interface in VSCode.
16+
*/
17+
interface MainThreadClipboardShape : Disposable {
18+
/**
19+
* Reads text from the clipboard.
20+
* @return The string from the clipboard, or null if no text is available
21+
*/
22+
fun readText(): String?
23+
24+
/**
25+
* Writes text to the clipboard.
26+
* @param value The string to write to the clipboard
27+
*/
28+
fun writeText(value: String?)
29+
}
30+
31+
/**
32+
* Implementation of the MainThreadClipboardShape interface.
33+
* Provides functionality to read from and write to the system clipboard.
34+
*/
35+
class MainThreadClipboard : MainThreadClipboardShape {
36+
private val logger = Logger.getInstance(MainThreadClipboardShape::class.java)
37+
38+
/**
39+
* Reads text from the system clipboard.
40+
*
41+
* @return The string from the clipboard, or null if no text is available or an error occurs
42+
*/
43+
override fun readText(): String? {
44+
logger.info("Reading clipboard text")
45+
return try {
46+
val clipboard = Toolkit.getDefaultToolkit().systemClipboard
47+
val data = clipboard.getContents(null)
48+
if (data != null && data.isDataFlavorSupported(DataFlavor.stringFlavor)) {
49+
data.getTransferData(DataFlavor.stringFlavor) as? String
50+
} else {
51+
null
52+
}
53+
} catch (e: Exception) {
54+
logger.error("Failed to read clipboard", e)
55+
null
56+
}
57+
}
58+
59+
/**
60+
* Writes text to the system clipboard.
61+
*
62+
* @param value The string to write to the clipboard
63+
*/
64+
override fun writeText(value: String?) {
65+
value?.let {
66+
logger.info("Writing clipboard text: $value")
67+
try {
68+
val clipboard = Toolkit.getDefaultToolkit().systemClipboard
69+
val selection = StringSelection(value)
70+
clipboard.setContents(selection, selection)
71+
} catch (e: Exception) {
72+
logger.error("Failed to write to clipboard", e)
73+
}
74+
}
75+
}
76+
77+
/**
78+
* Releases resources used by this clipboard handler.
79+
*/
80+
override fun dispose() {
81+
logger.info("Releasing resources: MainThreadClipboard")
82+
}
83+
}

0 commit comments

Comments
 (0)