mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[markdown] IJPL-177111 refactor Markdown components for consistency and clarity
GitOrigin-RevId: 531f7c07d9a8be35cf6db5bd56a7aaa66a07488c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
be919d5f08
commit
447cea89c5
@@ -5,8 +5,8 @@
|
||||
</dependencies>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<platform.rpc.backend.remoteApiProvider
|
||||
implementation="org.intellij.plugins.markdown.backend.providers.LinkOpenerApiProvider"/>
|
||||
implementation="org.intellij.plugins.markdown.backend.providers.MarkdownLinkOpenerApiProvider"/>
|
||||
<platform.rpc.backend.remoteApiProvider
|
||||
implementation="org.intellij.plugins.markdown.backend.providers.ProjectStructureProvider"/>
|
||||
implementation="org.intellij.plugins.markdown.backend.providers.VirtualFileAccessorProvider"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
+1
-1
@@ -5,7 +5,7 @@ import fleet.rpc.remoteApiDescriptor
|
||||
import org.intellij.plugins.markdown.backend.services.MarkdownLinkOpenerRemoteApiImpl
|
||||
import org.intellij.plugins.markdown.service.MarkdownLinkOpenerRemoteApi
|
||||
|
||||
private class LinkOpenerApiProvider : RemoteApiProvider {
|
||||
private class MarkdownLinkOpenerApiProvider : RemoteApiProvider {
|
||||
override fun RemoteApiProvider.Sink.remoteApis() {
|
||||
remoteApi(remoteApiDescriptor<MarkdownLinkOpenerRemoteApi>()) {
|
||||
MarkdownLinkOpenerRemoteApiImpl()
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
package org.intellij.plugins.markdown.backend.providers
|
||||
|
||||
import com.intellij.platform.rpc.backend.RemoteApiProvider
|
||||
import fleet.rpc.remoteApiDescriptor
|
||||
import org.intellij.plugins.markdown.backend.services.ProjectStructureRemoteApiImpl
|
||||
import org.intellij.plugins.markdown.service.ProjectStructureRemoteApi
|
||||
|
||||
private class ProjectStructureProvider : RemoteApiProvider {
|
||||
override fun RemoteApiProvider.Sink.remoteApis() {
|
||||
remoteApi(remoteApiDescriptor<ProjectStructureRemoteApi>()) {
|
||||
ProjectStructureRemoteApiImpl()
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.intellij.plugins.markdown.backend.providers
|
||||
|
||||
import com.intellij.platform.rpc.backend.RemoteApiProvider
|
||||
import fleet.rpc.remoteApiDescriptor
|
||||
import org.intellij.plugins.markdown.backend.services.VirtualFileAccessorImpl
|
||||
import org.intellij.plugins.markdown.service.VirtualFileAccessor
|
||||
|
||||
private class VirtualFileAccessorProvider : RemoteApiProvider {
|
||||
override fun RemoteApiProvider.Sink.remoteApis() {
|
||||
remoteApi(remoteApiDescriptor<VirtualFileAccessor>()) {
|
||||
VirtualFileAccessorImpl()
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-5
@@ -9,11 +9,11 @@ import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.project.ProjectId
|
||||
import com.intellij.platform.project.findProject
|
||||
import org.intellij.plugins.markdown.service.ProjectStructureRemoteApi
|
||||
import org.intellij.plugins.markdown.service.VirtualFileAccessor
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
class ProjectStructureRemoteApiImpl : ProjectStructureRemoteApi {
|
||||
class VirtualFileAccessorImpl : VirtualFileAccessor {
|
||||
private fun getBaseDirectory(projectId: ProjectId, virtualFileId: VirtualFileId) : VirtualFile?{
|
||||
val project = projectId.findProject()
|
||||
val virtualFile = virtualFileId.virtualFile() ?: return null
|
||||
@@ -21,8 +21,7 @@ class ProjectStructureRemoteApiImpl : ProjectStructureRemoteApi {
|
||||
return baseDirectory
|
||||
}
|
||||
|
||||
override suspend fun getFileByResourceName(resourceName: String, virtualFileId: VirtualFileId?, projectId: ProjectId?): VirtualFileId? {
|
||||
if (projectId == null || virtualFileId == null) return null
|
||||
override suspend fun getFileByResourceName(resourceName: String, virtualFileId: VirtualFileId, projectId: ProjectId): VirtualFileId? {
|
||||
val projectRoot = getBaseDirectory(projectId, virtualFileId)
|
||||
val resource = if (resourceName.startsWith("file:/")) {
|
||||
VfsUtil.findFileByIoFile(File(URL(resourceName).path), true)
|
||||
@@ -33,6 +32,6 @@ class ProjectStructureRemoteApiImpl : ProjectStructureRemoteApi {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger: Logger = Logger.getInstance(ProjectStructureRemoteApiImpl::class.java)
|
||||
private val logger: Logger = Logger.getInstance(VirtualFileAccessorImpl::class.java)
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -36,12 +36,13 @@ import org.intellij.plugins.markdown.settings.DocumentLinksSafeState
|
||||
import org.intellij.plugins.markdown.ui.MarkdownNotifications
|
||||
import org.intellij.plugins.markdown.ui.preview.accessor.MarkdownLinkOpener
|
||||
import org.intellij.plugins.markdown.ui.preview.accessor.MarkdownLinkOpenerUtil
|
||||
import org.intellij.plugins.markdown.ui.preview.accessor.MarkdownLinkOpenerUtil.Companion.findVirtualFile
|
||||
import org.intellij.plugins.markdown.ui.preview.accessor.MarkdownLinkOpenerUtil.findVirtualFile
|
||||
import org.intellij.plugins.markdown.util.MarkdownDisposable
|
||||
import java.net.URI
|
||||
import java.net.URISyntaxException
|
||||
|
||||
internal class MarkdownLinkOpenerImpl(val coroutineScope: CoroutineScope) : MarkdownLinkOpener {
|
||||
@Deprecated("Use openLink(project, link, sourceFile) instead", replaceWith = ReplaceWith("openLink(project, link, sourceFile)"))
|
||||
override fun openLink(project: Project?, link: String) {
|
||||
val uri = createUri(link) ?: return
|
||||
if (tryOpenInEditorDeprecated(project, uri)) {
|
||||
@@ -52,16 +53,15 @@ internal class MarkdownLinkOpenerImpl(val coroutineScope: CoroutineScope) : Mark
|
||||
}
|
||||
}
|
||||
|
||||
override fun openLink(project: Project?, link: String, containingFile: VirtualFile?) {
|
||||
override fun openLink(currentProject: Project?, link: String, containingFile: VirtualFile?) {
|
||||
coroutineScope.launch {
|
||||
val data = MarkdownLinkOpenerRemoteApi.getInstance().fetchLinkNavigationData(link, containingFile?.rpcId())
|
||||
val uri = createUri(data.uri) ?: return@launch
|
||||
if (uri.scheme != "file") {
|
||||
openExternalLink(project, uri)
|
||||
openExternalLink(currentProject, uri)
|
||||
return@launch
|
||||
}
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val project = project ?: data.projectId?.findProject() ?: return@launch
|
||||
val project = currentProject ?: data.projectId?.findProject() ?: return@launch
|
||||
val fileToOpen = data.virtualFileId?.virtualFile() ?: return@launch
|
||||
val anchor = uri.fragment
|
||||
if (anchor == null) {
|
||||
|
||||
+18
-20
@@ -8,14 +8,14 @@ import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.platform.project.projectId
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.intellij.plugins.markdown.extensions.MarkdownBrowserPreviewExtension
|
||||
import org.intellij.plugins.markdown.service.ProjectStructureRemoteApi
|
||||
import org.intellij.plugins.markdown.service.VirtualFileAccessor
|
||||
import org.intellij.plugins.markdown.ui.preview.MarkdownHtmlPanel
|
||||
import org.intellij.plugins.markdown.ui.preview.ResourceProvider
|
||||
|
||||
internal class ProcessImagesExtension(
|
||||
private val baseFile: VirtualFile?,
|
||||
private val project: Project?
|
||||
): ResourceProvider, MarkdownBrowserPreviewExtension {
|
||||
private val project: Project?,
|
||||
) : ResourceProvider, MarkdownBrowserPreviewExtension {
|
||||
override val resourceProvider: ResourceProvider = this
|
||||
|
||||
override fun canProvide(resourceName: String): Boolean {
|
||||
@@ -23,32 +23,30 @@ internal class ProcessImagesExtension(
|
||||
}
|
||||
|
||||
override fun loadResource(resourceName: String): ResourceProvider.Resource? {
|
||||
val baseFileId = baseFile?.rpcId()
|
||||
val projectId = project?.projectId()
|
||||
val baseFileId = baseFile?.rpcId() ?: return null
|
||||
val projectId = project?.projectId() ?: return null
|
||||
val resource = runBlocking {
|
||||
ProjectStructureRemoteApi.getInstance().getFileByResourceName(resourceName, baseFileId, projectId)?.virtualFile()
|
||||
VirtualFileAccessor.getInstance().getFileByResourceName(resourceName, baseFileId, projectId)?.virtualFile()
|
||||
} ?: return null
|
||||
return ResourceProvider.loadExternalResource(resource)
|
||||
}
|
||||
|
||||
override fun dispose() = Unit
|
||||
|
||||
companion object{
|
||||
fun hasImageExtension(name: String): Boolean {
|
||||
val lowerName = name.lowercase()
|
||||
return lowerName.endsWith(".jpeg") ||
|
||||
lowerName.endsWith(".jpg") ||
|
||||
lowerName.endsWith(".png") ||
|
||||
lowerName.endsWith(".gif") ||
|
||||
lowerName.endsWith(".bmp") ||
|
||||
lowerName.endsWith(".svg") ||
|
||||
lowerName.endsWith(".webp") ||
|
||||
lowerName.endsWith(".tiff") ||
|
||||
lowerName.endsWith(".tif")
|
||||
}
|
||||
private fun hasImageExtension(name: String): Boolean {
|
||||
val lowerName = name.lowercase()
|
||||
return lowerName.endsWith(".jpeg") ||
|
||||
lowerName.endsWith(".jpg") ||
|
||||
lowerName.endsWith(".png") ||
|
||||
lowerName.endsWith(".gif") ||
|
||||
lowerName.endsWith(".bmp") ||
|
||||
lowerName.endsWith(".svg") ||
|
||||
lowerName.endsWith(".webp") ||
|
||||
lowerName.endsWith(".tiff") ||
|
||||
lowerName.endsWith(".tif")
|
||||
}
|
||||
|
||||
class Provider: MarkdownBrowserPreviewExtension.Provider {
|
||||
class Provider : MarkdownBrowserPreviewExtension.Provider {
|
||||
override fun createBrowserExtension(panel: MarkdownHtmlPanel): MarkdownBrowserPreviewExtension {
|
||||
return ProcessImagesExtension(panel.virtualFile, panel.project)
|
||||
}
|
||||
|
||||
+5
-1
@@ -2,6 +2,7 @@
|
||||
package org.intellij.plugins.markdown.mapper;
|
||||
|
||||
import com.intellij.ide.vfs.VirtualFileId;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
@@ -13,9 +14,12 @@ import com.intellij.ide.vfs.VirtualFileIdKt;
|
||||
* Mapper class for converting a MarkdownHeader into a MarkdownHeaderInfo.
|
||||
*/
|
||||
public final class MarkdownHeaderMapper {
|
||||
private static final Logger logger = Logger.getInstance(MarkdownHeaderMapper.class);
|
||||
|
||||
public static MarkdownHeaderInfo map(MarkdownHeader header) {
|
||||
if (header == null) {
|
||||
throw new IllegalArgumentException("header cannot be null");
|
||||
logger.warn("Header is null, returning null");
|
||||
return null;
|
||||
}
|
||||
String headerText = header.getText();
|
||||
|
||||
|
||||
+4
-4
@@ -11,13 +11,13 @@ import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
@Rpc
|
||||
interface ProjectStructureRemoteApi : RemoteApi<Unit> {
|
||||
suspend fun getFileByResourceName(resourceName: String, virtualFileId: VirtualFileId?, projectId: ProjectId?): VirtualFileId?
|
||||
interface VirtualFileAccessor : RemoteApi<Unit> {
|
||||
suspend fun getFileByResourceName(resourceName: String, virtualFileId: VirtualFileId, projectId: ProjectId): VirtualFileId?
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
suspend fun getInstance(): ProjectStructureRemoteApi {
|
||||
return RemoteApiProviderService.resolve(remoteApiDescriptor<ProjectStructureRemoteApi>())
|
||||
suspend fun getInstance(): VirtualFileAccessor {
|
||||
return RemoteApiProviderService.resolve(remoteApiDescriptor<VirtualFileAccessor>())
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -22,6 +22,7 @@ interface MarkdownLinkOpener {
|
||||
*
|
||||
* Note: it is possible to add custom url handler with [com.intellij.ide.browsers.UrlOpener] EP.
|
||||
*/
|
||||
@Deprecated("this method lacks remote development support", ReplaceWith("openLink(project, link, sourceFile)"))
|
||||
fun openLink(project: Project?, link: String)
|
||||
|
||||
fun openLink(project: Project?, link: String, sourceFile: VirtualFile?)
|
||||
|
||||
+50
-52
@@ -25,63 +25,61 @@ import java.net.URISyntaxException
|
||||
import java.nio.file.Path
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
|
||||
class MarkdownLinkOpenerUtil {
|
||||
companion object{
|
||||
private val logger = logger<MarkdownLinkOpenerUtil>()
|
||||
object MarkdownLinkOpenerUtil {
|
||||
private val logger = logger<MarkdownLinkOpenerUtil>()
|
||||
|
||||
fun navigateToHeader(project: Project, headerInfo: MarkdownHeaderInfo) {
|
||||
val uri = createFileUri(headerInfo.filePath)
|
||||
if (uri == null) return
|
||||
val file = headerInfo.virtualFileId.virtualFile()
|
||||
if (file == null) return
|
||||
val manager = FileEditorManager.getInstance(project)
|
||||
val openedEditors = manager.getEditorList(file).stream()
|
||||
.filter { editor: FileEditor? -> editor is MarkdownEditorWithPreview }
|
||||
.map<MarkdownEditorWithPreview?> { editor: FileEditor? -> editor as MarkdownEditorWithPreview }
|
||||
.toList()
|
||||
val element = PsiUtilCore.getPsiFile(project, file).findElementAt(headerInfo.textOffset)
|
||||
if (element == null) return
|
||||
if (!openedEditors.isEmpty()) {
|
||||
for (editor in openedEditors) {
|
||||
PsiUtilCore.getElementAtOffset(PsiUtilCore.getPsiFile(project, file), element.getTextOffset())
|
||||
PsiNavigateUtil.navigate(element, true)
|
||||
}
|
||||
return
|
||||
fun navigateToHeader(project: Project, headerInfo: MarkdownHeaderInfo) {
|
||||
val uri = createFileUri(headerInfo.filePath)
|
||||
if (uri == null) return
|
||||
val file = headerInfo.virtualFileId.virtualFile()
|
||||
if (file == null) return
|
||||
val manager = FileEditorManager.getInstance(project)
|
||||
val openedEditors = manager.getEditorList(file).stream()
|
||||
.filter { editor: FileEditor? -> editor is MarkdownEditorWithPreview }
|
||||
.map<MarkdownEditorWithPreview?> { editor: FileEditor? -> editor as MarkdownEditorWithPreview }
|
||||
.toList()
|
||||
val element = PsiUtilCore.getPsiFile(project, file).findElementAt(headerInfo.textOffset)
|
||||
if (element == null) return
|
||||
if (!openedEditors.isEmpty()) {
|
||||
for (editor in openedEditors) {
|
||||
PsiUtilCore.getElementAtOffset(PsiUtilCore.getPsiFile(project, file), element.getTextOffset())
|
||||
PsiNavigateUtil.navigate(element, true)
|
||||
}
|
||||
val descriptor = OpenFileDescriptor(project, file, element.getTextOffset())
|
||||
manager.openEditor(descriptor, true)
|
||||
return
|
||||
}
|
||||
val descriptor = OpenFileDescriptor(project, file, element.getTextOffset())
|
||||
manager.openEditor(descriptor, true)
|
||||
}
|
||||
|
||||
fun collectHeaders(project: Project, anchor: String, targetFile: VirtualFile): List<MarkdownHeaderInfo>? {
|
||||
return runReadAction {
|
||||
if (DumbService.isDumb(project)) {
|
||||
return@runReadAction emptyList()
|
||||
}
|
||||
val scope = when (val file = PsiManager.getInstance(project).findFile(targetFile)) {
|
||||
null -> GlobalSearchScope.EMPTY_SCOPE
|
||||
else -> GlobalSearchScope.fileScope(file)
|
||||
}
|
||||
return@runReadAction HeaderAnchorIndex.collectHeaders(project, scope, anchor).map(MarkdownHeaderMapper::map)
|
||||
fun collectHeaders(project: Project, anchor: String, targetFile: VirtualFile): List<MarkdownHeaderInfo>? {
|
||||
return runReadAction {
|
||||
if (DumbService.isDumb(project)) {
|
||||
return@runReadAction emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
fun URI.findVirtualFile(): VirtualFile? {
|
||||
val actualPath = when {
|
||||
SystemInfo.isWindows -> UriUtil.trimLeadingSlashes(path)
|
||||
else -> path
|
||||
}
|
||||
val path = Path.of(actualPath)
|
||||
return VfsUtil.findFile(path, true)
|
||||
}
|
||||
|
||||
private fun createFileUri(link: String?): URI? {
|
||||
try {
|
||||
return URI("file", null, link, null)
|
||||
}
|
||||
catch (exception: URISyntaxException) {
|
||||
logger.warn(exception)
|
||||
return null
|
||||
val scope = when (val file = PsiManager.getInstance(project).findFile(targetFile)) {
|
||||
null -> GlobalSearchScope.EMPTY_SCOPE
|
||||
else -> GlobalSearchScope.fileScope(file)
|
||||
}
|
||||
return@runReadAction HeaderAnchorIndex.collectHeaders(project, scope, anchor).map(MarkdownHeaderMapper::map)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun URI.findVirtualFile(): VirtualFile? {
|
||||
val actualPath = when {
|
||||
SystemInfo.isWindows -> UriUtil.trimLeadingSlashes(path)
|
||||
else -> path
|
||||
}
|
||||
val path = Path.of(actualPath)
|
||||
return VfsUtil.findFile(path, true)
|
||||
}
|
||||
|
||||
private fun createFileUri(link: String?): URI? {
|
||||
try {
|
||||
return URI("file", null, link, null)
|
||||
}
|
||||
catch (exception: URISyntaxException) {
|
||||
logger.warn(exception)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user