From 2732fd529457e2b3f7f7608ace181fbf64b626c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=8E=E5=A3=B0?= Date: Tue, 24 Sep 2024 17:13:49 +0800 Subject: [PATCH] feat: support render image --- .../static-resource.contribution.ts | 66 +++++++++++++++++++ .../core/src/core/editor/editor.module.ts | 4 +- packages/core/src/core/editor/types.ts | 4 ++ packages/core/src/core/utils.ts | 48 +++++++++++++- packages/startup/src/editor/index.tsx | 19 +++++- packages/sumi-core/src/common/types.ts | 3 +- 6 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 packages/core/src/core/editor/contributions/static-resource.contribution.ts diff --git a/packages/core/src/core/editor/contributions/static-resource.contribution.ts b/packages/core/src/core/editor/contributions/static-resource.contribution.ts new file mode 100644 index 00000000..b0b6f061 --- /dev/null +++ b/packages/core/src/core/editor/contributions/static-resource.contribution.ts @@ -0,0 +1,66 @@ +import { Autowired, Injectable } from '@opensumi/di'; +import { AppConfig, Domain, path as paths, URI } from '@opensumi/ide-core-browser'; +import { + StaticResourceContribution as CoreStaticResourceContribution, + StaticResourceService, +} from '@opensumi/ide-core-browser/lib/static-resource'; +import { IWorkspaceService } from '@opensumi/ide-workspace'; +import { IPropsService } from '../../props.service'; +import { fromSCMUri } from '../../utils'; +import { CodeDocumentModel, EditorProps } from '../types'; + +const EXPRESS_SERVER_PATH = window.location.href; + +// file 文件资源 远程读取 +@Domain(CoreStaticResourceContribution) +export class EditorStaticResourceContribution implements CoreStaticResourceContribution { + @Autowired(AppConfig) + private readonly appConfig: AppConfig; + + @Autowired(IWorkspaceService) + private readonly workspaceService: IWorkspaceService; + + @Autowired(IPropsService) + propsService: IPropsService; + + registerStaticResolver(service: StaticResourceService): void { + // 用来打开 raw 文件,如 jpg + service.registerStaticResourceProvider({ + scheme: 'file', + resolveStaticResource: (uri: URI) => { + const documentModel = this.propsService.props.documentModel; + + if ( + !(this.appConfig.staticServicePath + || (documentModel && (documentModel as CodeDocumentModel).resolveStaticResourcePath)) + ) { + return uri; + } + + // 将 file 协议转为代码托管平台提供的 raw 服务 + const assetsUri = new URI(this.appConfig.staticServicePath!); + const rootUri = new URI(this.workspaceService.workspace?.uri!); + const relativePath = rootUri.relative(uri); + if (!relativePath) { + return uri; + } + + // FIXME: 由于 resolveStaticResource 是同步方法,这里 hardcode 了 workspaceManagerService 的实现 + let relativePathStr = relativePath.toString(); + + // trim leading whitespace + if (relativePathStr.startsWith(paths.Path.separator)) { + relativePathStr = relativePathStr.slice(1); + } + + if (documentModel && (documentModel as CodeDocumentModel).resolveStaticResourcePath) { + return (documentModel as CodeDocumentModel).resolveStaticResourcePath!( + documentModel as CodeDocumentModel, + ); + } + return assetsUri.withPath(assetsUri.path.join(relativePathStr)); + }, + roots: [this.appConfig.staticServicePath || EXPRESS_SERVER_PATH], + }); + } +} diff --git a/packages/core/src/core/editor/editor.module.ts b/packages/core/src/core/editor/editor.module.ts index 1943c0ed..18b0265d 100644 --- a/packages/core/src/core/editor/editor.module.ts +++ b/packages/core/src/core/editor/editor.module.ts @@ -58,9 +58,10 @@ import md5 from 'md5'; import * as path from 'path'; import { CodeBlitzCommandContribution } from '../commands'; import { IPropsService } from '../props.service'; +import { DefaultThemeGuardContribution } from '../providers'; import styles from '../style.module.less'; +import { EditorStaticResourceContribution } from './contributions/static-resource.contribution'; import { CodeDocumentModel, EditorProps, isCodeDocumentModel } from './types'; -import { DefaultThemeGuardContribution } from '../providers'; const ContextTrue = new RawContextKey('alex.context.true', undefined); const ContextFalse = new RawContextKey('alex.context.false', undefined); @@ -740,5 +741,6 @@ export class EditorSpecialModule extends BrowserModule { DefaultThemeGuardContribution, EditorSpecialContribution, CodeBlitzCommandContribution, + EditorStaticResourceContribution, ]; } diff --git a/packages/core/src/core/editor/types.ts b/packages/core/src/core/editor/types.ts index ce26e04b..c7dd3193 100644 --- a/packages/core/src/core/editor/types.ts +++ b/packages/core/src/core/editor/types.ts @@ -1,3 +1,5 @@ +import { URI } from '@opensumi/ide-core-common'; + export interface DocumentModel { /** * 打开的文件路径 @@ -48,6 +50,8 @@ export interface CodeDocumentModel extends DocumentModel { * 仓库名 */ name: string; + + resolveStaticResourcePath?(documentModel: CodeDocumentModel): URI; } export interface EditorConfig { diff --git a/packages/core/src/core/utils.ts b/packages/core/src/core/utils.ts index ba6ab1aa..67a8d840 100644 --- a/packages/core/src/core/utils.ts +++ b/packages/core/src/core/utils.ts @@ -1,7 +1,6 @@ -import { IExtensionBasicMetadata } from '@codeblitzjs/ide-common'; import { IAppOpts } from '@codeblitzjs/ide-sumi-core'; import { ModuleConstructor } from '@opensumi/ide-core-browser'; -import { BuiltinTheme, getThemeId, getThemeType, IThemeContribution } from '@opensumi/ide-theme'; +import { URI } from '@opensumi/ide-core-common'; import { IAppConfig } from '../api/types'; @@ -68,3 +67,48 @@ export function createHook(obj: any, targetFunction: string, options: { } }; } + +interface SCMUriQueryParams { + ref: string; // commitId + branch?: string; // 分支名 +} + +interface SCMUriParams extends SCMUriQueryParams { + platform: string; // 例如 gitlab/gitlab 等 + repo: string; // groupName/repoName 项目名称 + path: string; // 文件路径 +} + +export function fromSCMUri(uri: URI): SCMUriParams { + const query = uri.getParsedQuery(); + + const result: SCMUriParams = { + platform: query.scheme, + repo: query.authority, + path: query.path, + ref: query.ref, + }; + + if (query.branch) { + result.branch = query.branch; + } + + return result; +} + +export function toSCMUri(uriParams: SCMUriParams) { + const query: SCMUriQueryParams = { + ref: uriParams.ref, + }; + + if (uriParams.branch) { + query.branch = uriParams.branch; + } + + return URI.from({ + scheme: uriParams.platform, + authority: uriParams.repo, + path: uriParams.path, + query: JSON.stringify(query), + }); +} diff --git a/packages/startup/src/editor/index.tsx b/packages/startup/src/editor/index.tsx index e17982a0..9958a417 100644 --- a/packages/startup/src/editor/index.tsx +++ b/packages/startup/src/editor/index.tsx @@ -12,6 +12,10 @@ import Cascader from 'antd/lib/cascader'; import Select from 'antd/lib/select'; import './style.less'; import { request } from '@codeblitzjs/ide-common'; +import { URI } from '@opensumi/ide-core-common'; + +import { CodeDocumentModel } from '@codeblitzjs/ide-core/lib/core/editor/types'; +import { getFileTypeByExt } from '@codeblitzjs/ide-core/lib/modules/opensumi__ide-file-service'; import { LocalExtensionModule } from '../common/local-extension.module'; import * as editorPlugin from './plugin'; @@ -29,7 +33,7 @@ const fileOptions = (function transform(obj) { }); })({ 'opensumi/core': { - main: ['README.md', 'package.json'], + main: ['README.md', 'package.json', 'packages/design/src/browser/style/images/design-background-light.png'], }, }); @@ -46,6 +50,8 @@ const App = () => { [30, 40], ]); + const staticServicePath = `https://raw.githubusercontent.com`; + const readFile = async (filepath: string) => { const res = await request( `https://api.github.com/repos/${project}/contents/${filepath}?ref=${ref}`, @@ -170,7 +176,11 @@ const App = () => { startupEditor: 'none', // hideEditorTab: true, resolveFileType(path) { - return 'text'; + const ext = path.split('.').pop(); + if (!ext) { + return 'text'; + } + return getFileTypeByExt(ext); }, }} editorConfig={{ @@ -194,6 +204,11 @@ const App = () => { onLineNumberChange(num) { setLineNumber(num); }, + resolveStaticResourcePath(documentModel: CodeDocumentModel) { + return URI.parse( + `${staticServicePath}/${documentModel.owner}/${documentModel.name}/${documentModel.ref}/${documentModel.filepath}`, + ); + }, }} /> ) diff --git a/packages/sumi-core/src/common/types.ts b/packages/sumi-core/src/common/types.ts index 345a1823..65a53678 100644 --- a/packages/sumi-core/src/common/types.ts +++ b/packages/sumi-core/src/common/types.ts @@ -8,6 +8,7 @@ import { IChatProgress, IReporter, } from '@opensumi/ide-core-common'; +import { EditorFileType } from '@opensumi/ide-file-service/lib/common'; import { ITheme } from '@opensumi/ide-theme'; import { SumiReadableStream } from '@opensumi/ide-utils/lib/stream'; import { FileSystemConfiguration, FileSystemInstance } from '../server/node'; @@ -212,7 +213,7 @@ export interface RuntimeConfig { * 当文件后缀名判断格式 不满足条件时,可通过此配置项进行自定义 * 优先会从语法服务中获取类型 */ - resolveFileType?: (path: string) => 'image' | 'text' | 'video' | undefined; + resolveFileType?: (path: string) => 'image' | 'text' | 'video' | undefined | EditorFileType; /** * AI Native 相关配置