mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
Merge pull request #3 from commandlinedev/CLI-9-Create-a-new-Plugin-called-CodeRenderer
Cli 9 create a new plugin called code renderer
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
"main": "dist/emain.js",
|
||||
"license": "Proprietary",
|
||||
"dependencies": {
|
||||
"@monaco-editor/react": "^4.5.1",
|
||||
"autobind-decorator": "^2.4.0",
|
||||
"classnames": "^2.3.1",
|
||||
"dayjs": "^1.11.3",
|
||||
|
||||
+1220
-845
File diff suppressed because it is too large
Load Diff
+4032
-3346
File diff suppressed because it is too large
Load Diff
+93
-76
@@ -1,93 +1,110 @@
|
||||
import {RendererPluginType} from "./types";
|
||||
import {SimpleImageRenderer} from "./view/image";
|
||||
import {SimpleMarkdownRenderer} from "./view/markdown";
|
||||
import {SimpleJsonRenderer} from "./view/json";
|
||||
import {OpenAIRenderer, OpenAIRendererModel} from "./view/openai";
|
||||
import {isBlank} from "./util";
|
||||
import {sprintf} from "sprintf-js";
|
||||
import { RendererPluginType } from "./types";
|
||||
import { SimpleImageRenderer } from "./view/image";
|
||||
import { SimpleMarkdownRenderer } from "./view/markdown";
|
||||
import { SimpleJsonRenderer } from "./view/json";
|
||||
import { SourceCodeRenderer } from "./view/code";
|
||||
import { OpenAIRenderer, OpenAIRendererModel } from "./view/openai";
|
||||
import { isBlank } from "./util";
|
||||
import { sprintf } from "sprintf-js";
|
||||
|
||||
const ImagePlugin : RendererPluginType = {
|
||||
name: "image",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["image/*"],
|
||||
simpleComponent: SimpleImageRenderer,
|
||||
const ImagePlugin: RendererPluginType = {
|
||||
name: "image",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["image/*"],
|
||||
simpleComponent: SimpleImageRenderer,
|
||||
};
|
||||
|
||||
const MarkdownPlugin : RendererPluginType = {
|
||||
name: "markdown",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["text/markdown"],
|
||||
simpleComponent: SimpleMarkdownRenderer,
|
||||
const MarkdownPlugin: RendererPluginType = {
|
||||
name: "markdown",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["text/markdown"],
|
||||
simpleComponent: SimpleMarkdownRenderer,
|
||||
};
|
||||
|
||||
const JsonPlugin : RendererPluginType = {
|
||||
name: "json",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["application/json"],
|
||||
simpleComponent: SimpleJsonRenderer,
|
||||
const JsonPlugin: RendererPluginType = {
|
||||
name: "json",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["application/json"],
|
||||
simpleComponent: SimpleJsonRenderer,
|
||||
};
|
||||
|
||||
const OpenAIPlugin : RendererPluginType = {
|
||||
name: "openai",
|
||||
rendererType: "full",
|
||||
heightType: "pixels",
|
||||
dataType: "model",
|
||||
collapseType: "remove",
|
||||
hidePrompt: true,
|
||||
globalCss: null,
|
||||
mimeTypes: ["application/json"],
|
||||
fullComponent: OpenAIRenderer,
|
||||
modelCtor: () => new OpenAIRendererModel(),
|
||||
const CodePlugin: RendererPluginType = {
|
||||
name: "code",
|
||||
rendererType: "simple",
|
||||
heightType: "pixels",
|
||||
dataType: "blob",
|
||||
collapseType: "hide",
|
||||
globalCss: null,
|
||||
mimeTypes: ["text/plain"],
|
||||
simpleComponent: SourceCodeRenderer,
|
||||
};
|
||||
|
||||
const OpenAIPlugin: RendererPluginType = {
|
||||
name: "openai",
|
||||
rendererType: "full",
|
||||
heightType: "pixels",
|
||||
dataType: "model",
|
||||
collapseType: "remove",
|
||||
hidePrompt: true,
|
||||
globalCss: null,
|
||||
mimeTypes: ["application/json"],
|
||||
fullComponent: OpenAIRenderer,
|
||||
modelCtor: () => new OpenAIRendererModel(),
|
||||
};
|
||||
|
||||
class PluginModelClass {
|
||||
rendererPlugins : RendererPluginType[] = [];
|
||||
|
||||
registerRendererPlugin(plugin : RendererPluginType) {
|
||||
if (isBlank(plugin.name)) {
|
||||
throw new Error("invalid plugin, no name");
|
||||
}
|
||||
if (plugin.name == "terminal" || plugin.name == "none") {
|
||||
throw new Error(sprintf("invalid plugin, name '%s' is reserved", plugin.name));
|
||||
}
|
||||
let existingPlugin = this.getRendererPluginByName(plugin.name);
|
||||
if (existingPlugin != null) {
|
||||
throw new Error(sprintf("plugin with name %s already registered", plugin.name));
|
||||
}
|
||||
this.rendererPlugins.push(plugin);
|
||||
}
|
||||
rendererPlugins: RendererPluginType[] = [];
|
||||
|
||||
getRendererPluginByName(name : string) : RendererPluginType {
|
||||
for (let i=0; i<this.rendererPlugins.length; i++) {
|
||||
let plugin = this.rendererPlugins[i];
|
||||
if (plugin.name == name) {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
registerRendererPlugin(plugin: RendererPluginType) {
|
||||
if (isBlank(plugin.name)) {
|
||||
throw new Error("invalid plugin, no name");
|
||||
}
|
||||
if (plugin.name == "terminal" || plugin.name == "none") {
|
||||
throw new Error(
|
||||
sprintf("invalid plugin, name '%s' is reserved", plugin.name)
|
||||
);
|
||||
}
|
||||
let existingPlugin = this.getRendererPluginByName(plugin.name);
|
||||
if (existingPlugin != null) {
|
||||
throw new Error(
|
||||
sprintf("plugin with name %s already registered", plugin.name)
|
||||
);
|
||||
}
|
||||
this.rendererPlugins.push(plugin);
|
||||
}
|
||||
|
||||
getRendererPluginByName(name: string): RendererPluginType {
|
||||
for (let i = 0; i < this.rendererPlugins.length; i++) {
|
||||
let plugin = this.rendererPlugins[i];
|
||||
if (plugin.name == name) {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let PluginModel : PluginModelClass = null;
|
||||
let PluginModel: PluginModelClass = null;
|
||||
if ((window as any).PluginModel == null) {
|
||||
PluginModel = new PluginModelClass();
|
||||
PluginModel.registerRendererPlugin(ImagePlugin);
|
||||
PluginModel.registerRendererPlugin(MarkdownPlugin);
|
||||
PluginModel.registerRendererPlugin(JsonPlugin);
|
||||
PluginModel.registerRendererPlugin(OpenAIPlugin);
|
||||
(window as any).PluginModel = PluginModel;
|
||||
PluginModel = new PluginModelClass();
|
||||
PluginModel.registerRendererPlugin(ImagePlugin);
|
||||
PluginModel.registerRendererPlugin(MarkdownPlugin);
|
||||
PluginModel.registerRendererPlugin(JsonPlugin);
|
||||
PluginModel.registerRendererPlugin(CodePlugin);
|
||||
PluginModel.registerRendererPlugin(OpenAIPlugin);
|
||||
(window as any).PluginModel = PluginModel;
|
||||
}
|
||||
|
||||
export {PluginModel};
|
||||
export { PluginModel };
|
||||
|
||||
+205
-197
@@ -39,7 +39,7 @@
|
||||
@import "views.less";
|
||||
@import "sidebar.less";
|
||||
@import "modals.less"; // includes settings
|
||||
@import "comps.less"; // includes terminal
|
||||
@import "comps.less"; // includes terminal
|
||||
@import "tabs.less";
|
||||
@import "cmdinput.less";
|
||||
@import "lines.less";
|
||||
@@ -47,251 +47,259 @@
|
||||
// global settings / overrides
|
||||
|
||||
:root {
|
||||
--fa-style-family: "Font Awesome 6 Sharp";
|
||||
--fa-style-family: "Font Awesome 6 Sharp";
|
||||
}
|
||||
|
||||
html, body, #app, #main {
|
||||
background-color: #000;
|
||||
height: 100vh;
|
||||
html,
|
||||
body,
|
||||
#app,
|
||||
#main {
|
||||
background-color: #000;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.content {
|
||||
a:hover {
|
||||
color: #485fc7;
|
||||
}
|
||||
a:hover {
|
||||
color: #485fc7;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
background-color: #777;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background-color: #777;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: white;
|
||||
background: white;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
cursor: pointer;
|
||||
input[type="checkbox"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
// main layout
|
||||
#main {
|
||||
height: 100vh;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
background-color: black;
|
||||
height: 100%;
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: black;
|
||||
height: 100%;
|
||||
.session-view,
|
||||
.history-view,
|
||||
.bookmarks-view {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 300px;
|
||||
position: relative;
|
||||
|
||||
.session-view, .history-view, .bookmarks-view {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 300px;
|
||||
position: relative;
|
||||
|
||||
&.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.screen-view {
|
||||
flex-grow: 1;
|
||||
border-right: 1px solid #ccc;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.window-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
.rendermode-tag {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background-color: rgba(78, 154, 6, 0.65);
|
||||
color: black;
|
||||
padding: 2px 8px 2px 4px;
|
||||
border-bottom-left-radius: 5px;
|
||||
z-index: 10;
|
||||
font-size: 12px;
|
||||
|
||||
&.is-active {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.render-mode {
|
||||
padding-top: 2px;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
color: #ccc;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.share-tag {
|
||||
color: #ccc;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 40%;
|
||||
background-color: darken(rgb(0, 177, 10), 20%);
|
||||
padding: 2px 8px 2px 4px;
|
||||
z-index: 11;
|
||||
font-size: 12px;
|
||||
/* border-radius: 0 0 5px 5px; */
|
||||
opacity: 0.8;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.share-tag-link {
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.share-tag-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
opacity: 1.0;
|
||||
padding: 20px;
|
||||
width: 250px;
|
||||
border: 1px solid #ccc;
|
||||
border-top: 0;
|
||||
|
||||
.share-tag-link {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.window-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
color: #ccc;
|
||||
.mono-font();
|
||||
|
||||
code {
|
||||
background-color: black;
|
||||
color: #4e9a06;
|
||||
}
|
||||
|
||||
&.should-fade {
|
||||
opacity: 1.0;
|
||||
animation: fade-in 2.5s;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.screen-view {
|
||||
flex-grow: 1;
|
||||
border-right: 1px solid #ccc;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.window-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
.rendermode-tag {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background-color: rgba(78, 154, 6, 0.65);
|
||||
color: black;
|
||||
padding: 2px 8px 2px 4px;
|
||||
border-bottom-left-radius: 5px;
|
||||
z-index: 10;
|
||||
font-size: 12px;
|
||||
|
||||
&.is-active {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.render-mode {
|
||||
padding-top: 2px;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
color: #ccc;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.share-tag {
|
||||
color: #ccc;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 40%;
|
||||
background-color: darken(rgb(0, 177, 10), 20%);
|
||||
padding: 2px 8px 2px 4px;
|
||||
z-index: 11;
|
||||
font-size: 12px;
|
||||
/* border-radius: 0 0 5px 5px; */
|
||||
opacity: 0.8;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.share-tag-link {
|
||||
margin-top: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.share-tag-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
opacity: 1;
|
||||
padding: 20px;
|
||||
width: 250px;
|
||||
border: 1px solid #ccc;
|
||||
border-top: 0;
|
||||
|
||||
.share-tag-link {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.window-empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
color: #ccc;
|
||||
.mono-font();
|
||||
|
||||
code {
|
||||
background-color: black;
|
||||
color: #4e9a06;
|
||||
}
|
||||
|
||||
&.should-fade {
|
||||
opacity: 1;
|
||||
animation: fade-in 2.5s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remote-field .remote-status {
|
||||
top: 4px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.image-renderer {
|
||||
padding: 10px;
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
padding: 10px;
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.renderer-container {
|
||||
.error-container {
|
||||
color: @term-red;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
}
|
||||
.error-container {
|
||||
color: @term-red;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.scroller {
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.renderer-container.code-renderer {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.renderer-container.json-renderer {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown-renderer .markdown {
|
||||
padding: 5px;
|
||||
line-height: 1.5;
|
||||
width: fit-content;
|
||||
padding: 5px;
|
||||
line-height: 1.5;
|
||||
width: fit-content;
|
||||
|
||||
blockquote {
|
||||
background-color: #222;
|
||||
}
|
||||
blockquote {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
code {
|
||||
background-color: #222;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #222;
|
||||
margin: 2px 10px 6px 10px;
|
||||
padding: 4px 4px 4px 6px;
|
||||
}
|
||||
pre {
|
||||
background-color: #222;
|
||||
margin: 2px 10px 6px 10px;
|
||||
padding: 4px 4px 4px 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.openai-renderer {
|
||||
.openai-message {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
|
||||
.openai-role {
|
||||
color: @term-bright-green;
|
||||
font-weight: bold;
|
||||
width: 100px;
|
||||
}
|
||||
.openai-message {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
|
||||
.openai-role.openai-role-assistant {
|
||||
color: @term-bright-white;
|
||||
}
|
||||
|
||||
.openai-content-user {
|
||||
white-space: pre;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.openai-content-assistant {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.openai-role-error {
|
||||
color: @term-bright-red;
|
||||
}
|
||||
|
||||
.openai-content-error {
|
||||
color: @term-bright-red;
|
||||
}
|
||||
.openai-role {
|
||||
color: @term-bright-green;
|
||||
font-weight: bold;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.openai-role.openai-role-assistant {
|
||||
color: @term-bright-white;
|
||||
}
|
||||
|
||||
.openai-content-user {
|
||||
white-space: pre;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.openai-content-assistant {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.openai-role-error {
|
||||
color: @term-bright-red;
|
||||
}
|
||||
|
||||
.openai-content-error {
|
||||
color: @term-bright-red;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+196
-149
@@ -1,182 +1,229 @@
|
||||
import * as React from "react";
|
||||
import * as mobxReact from "mobx-react";
|
||||
import * as mobx from "mobx";
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {boundMethod} from "autobind-decorator";
|
||||
import {If, For, When, Otherwise, Choose} from "tsx-control-statements/components";
|
||||
import type {RendererModelInitializeParams, TermOptsType, RendererContext, RendererOpts, SimpleBlobRendererComponent, RendererModelContainerApi, RendererPluginType, PtyDataType, RendererModel, RendererOptsUpdate, LineType, TermContextUnion, RendererContainerType} from "./types";
|
||||
import {PacketDataBuffer} from "./ptydata";
|
||||
import {debounce, throttle} from "throttle-debounce";
|
||||
import { sprintf } from "sprintf-js";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import {
|
||||
If,
|
||||
For,
|
||||
When,
|
||||
Otherwise,
|
||||
Choose,
|
||||
} from "tsx-control-statements/components";
|
||||
import type {
|
||||
RendererModelInitializeParams,
|
||||
TermOptsType,
|
||||
RendererContext,
|
||||
RendererOpts,
|
||||
SimpleBlobRendererComponent,
|
||||
RendererModelContainerApi,
|
||||
RendererPluginType,
|
||||
PtyDataType,
|
||||
RendererModel,
|
||||
RendererOptsUpdate,
|
||||
LineType,
|
||||
TermContextUnion,
|
||||
RendererContainerType,
|
||||
} from "./types";
|
||||
import { PacketDataBuffer } from "./ptydata";
|
||||
import { debounce, throttle } from "throttle-debounce";
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
type CV<V> = mobx.IComputedValue<V>;
|
||||
|
||||
class SimpleBlobRendererModel {
|
||||
context : RendererContext;
|
||||
opts : RendererOpts;
|
||||
isDone : OV<boolean>;
|
||||
api : RendererModelContainerApi;
|
||||
savedHeight : number;
|
||||
loading : OV<boolean>;
|
||||
loadError : OV<string> = mobx.observable.box(null, {name: "renderer-loadError"});
|
||||
ptyData : PtyDataType;
|
||||
ptyDataSource : (termContext : TermContextUnion) => Promise<PtyDataType>;
|
||||
|
||||
initialize(params : RendererModelInitializeParams) : void {
|
||||
this.loading = mobx.observable.box(true, {name: "renderer-loading"});
|
||||
this.isDone = mobx.observable.box(params.isDone, {name: "renderer-isDone"});
|
||||
this.context = params.context;
|
||||
this.opts = params.opts;
|
||||
this.api = params.api;
|
||||
this.savedHeight = params.savedHeight;
|
||||
this.ptyDataSource = params.ptyDataSource;
|
||||
if (this.isDone.get()) {
|
||||
setTimeout(() => this.reload(0), 10);
|
||||
}
|
||||
}
|
||||
context: RendererContext;
|
||||
opts: RendererOpts;
|
||||
isDone: OV<boolean>;
|
||||
api: RendererModelContainerApi;
|
||||
savedHeight: number;
|
||||
loading: OV<boolean>;
|
||||
loadError: OV<string> = mobx.observable.box(null, {
|
||||
name: "renderer-loadError",
|
||||
});
|
||||
ptyData: PtyDataType;
|
||||
ptyDataSource: (termContext: TermContextUnion) => Promise<PtyDataType>;
|
||||
|
||||
dispose() : void {
|
||||
return;
|
||||
}
|
||||
|
||||
giveFocus() : void {
|
||||
return;
|
||||
initialize(params: RendererModelInitializeParams): void {
|
||||
this.loading = mobx.observable.box(true, { name: "renderer-loading" });
|
||||
this.isDone = mobx.observable.box(params.isDone, {
|
||||
name: "renderer-isDone",
|
||||
});
|
||||
this.context = params.context;
|
||||
this.opts = params.opts;
|
||||
this.api = params.api;
|
||||
this.savedHeight = params.savedHeight;
|
||||
this.ptyDataSource = params.ptyDataSource;
|
||||
if (this.isDone.get()) {
|
||||
setTimeout(() => this.reload(0), 10);
|
||||
}
|
||||
}
|
||||
|
||||
updateOpts(update : RendererOptsUpdate) : void {
|
||||
Object.assign(this.opts, update);
|
||||
}
|
||||
dispose(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
updateHeight(newHeight : number) : void {
|
||||
if (this.savedHeight != newHeight) {
|
||||
this.savedHeight = newHeight;
|
||||
this.api.saveHeight(newHeight);
|
||||
}
|
||||
giveFocus(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
updateOpts(update: RendererOptsUpdate): void {
|
||||
Object.assign(this.opts, update);
|
||||
}
|
||||
|
||||
updateHeight(newHeight: number): void {
|
||||
if (this.savedHeight != newHeight) {
|
||||
this.savedHeight = newHeight;
|
||||
this.api.saveHeight(newHeight);
|
||||
}
|
||||
|
||||
setIsDone() : void {
|
||||
if (this.isDone.get()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setIsDone(): void {
|
||||
if (this.isDone.get()) {
|
||||
return;
|
||||
}
|
||||
mobx.action(() => {
|
||||
this.isDone.set(true);
|
||||
})();
|
||||
this.reload(0);
|
||||
}
|
||||
|
||||
reload(delayMs: number): void {
|
||||
mobx.action(() => {
|
||||
this.loading.set(true);
|
||||
})();
|
||||
let rtnp = this.ptyDataSource(this.context);
|
||||
if (rtnp == null) {
|
||||
console.log(
|
||||
"no promise returned from ptyDataSource (simplerenderer)",
|
||||
this.context
|
||||
);
|
||||
return;
|
||||
}
|
||||
rtnp
|
||||
.then((ptydata) => {
|
||||
setTimeout(() => {
|
||||
this.ptyData = ptydata;
|
||||
mobx.action(() => {
|
||||
this.loading.set(false);
|
||||
this.loadError.set(null);
|
||||
})();
|
||||
}, delayMs);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("error loading data", e);
|
||||
mobx.action(() => {
|
||||
this.isDone.set(true);
|
||||
this.loadError.set("error loading data: " + e);
|
||||
})();
|
||||
this.reload(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reload(delayMs : number) : void {
|
||||
mobx.action(() => {
|
||||
this.loading.set(true);
|
||||
})();
|
||||
let rtnp = this.ptyDataSource(this.context);
|
||||
if (rtnp == null) {
|
||||
console.log("no promise returned from ptyDataSource (simplerenderer)", this.context);
|
||||
return;
|
||||
}
|
||||
rtnp.then((ptydata) => {
|
||||
setTimeout(() => {
|
||||
this.ptyData = ptydata;
|
||||
mobx.action(() => {
|
||||
this.loading.set(false);
|
||||
this.loadError.set(null);
|
||||
})();
|
||||
}, delayMs);
|
||||
}).catch((e) => {
|
||||
console.log("error loading data", e);
|
||||
mobx.action(() => {
|
||||
this.loadError.set("error loading data: " + e);
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
receiveData(pos : number, data : Uint8Array, reason? : string) : void {
|
||||
// this.dataBuf.receiveData(pos, data, reason);
|
||||
}
|
||||
receiveData(pos: number, data: Uint8Array, reason?: string): void {
|
||||
// this.dataBuf.receiveData(pos, data, reason);
|
||||
}
|
||||
}
|
||||
|
||||
@mobxReact.observer
|
||||
class SimpleBlobRenderer extends React.Component<{rendererContainer : RendererContainerType, lineId : string, plugin : RendererPluginType, onHeightChange : () => void, initParams : RendererModelInitializeParams}, {}> {
|
||||
model : SimpleBlobRendererModel;
|
||||
wrapperDivRef : React.RefObject<any> = React.createRef();
|
||||
rszObs : ResizeObserver;
|
||||
updateHeight_debounced : (newHeight : number) => void;
|
||||
class SimpleBlobRenderer extends React.Component<
|
||||
{
|
||||
rendererContainer: RendererContainerType;
|
||||
lineId: string;
|
||||
plugin: RendererPluginType;
|
||||
onHeightChange: () => void;
|
||||
initParams: RendererModelInitializeParams;
|
||||
},
|
||||
{}
|
||||
> {
|
||||
model: SimpleBlobRendererModel;
|
||||
wrapperDivRef: React.RefObject<any> = React.createRef();
|
||||
rszObs: ResizeObserver;
|
||||
updateHeight_debounced: (newHeight: number) => void;
|
||||
|
||||
constructor(props : any) {
|
||||
super(props);
|
||||
let {rendererContainer, lineId, plugin, initParams} = this.props;
|
||||
this.model = new SimpleBlobRendererModel();
|
||||
this.model.initialize(initParams);
|
||||
rendererContainer.registerRenderer(lineId, this.model);
|
||||
this.updateHeight_debounced = debounce(1000, this.updateHeight.bind(this));
|
||||
}
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
let { rendererContainer, lineId, plugin, initParams } = this.props;
|
||||
this.model = new SimpleBlobRendererModel();
|
||||
this.model.initialize(initParams);
|
||||
rendererContainer.registerRenderer(lineId, this.model);
|
||||
this.updateHeight_debounced = debounce(1000, this.updateHeight.bind(this));
|
||||
}
|
||||
|
||||
updateHeight(newHeight : number) : void {
|
||||
this.model.updateHeight(newHeight);
|
||||
}
|
||||
updateHeight(newHeight: number): void {
|
||||
this.model.updateHeight(newHeight);
|
||||
}
|
||||
|
||||
handleResize(entries : ResizeObserverEntry[]) : void {
|
||||
if (this.model.loading.get()) {
|
||||
return;
|
||||
}
|
||||
if (this.props.onHeightChange) {
|
||||
this.props.onHeightChange();
|
||||
}
|
||||
if (!this.model.loading.get() && this.wrapperDivRef.current != null) {
|
||||
let height = this.wrapperDivRef.current.offsetHeight;
|
||||
this.updateHeight_debounced(height);
|
||||
}
|
||||
handleResize(entries: ResizeObserverEntry[]): void {
|
||||
if (this.model.loading.get()) {
|
||||
return;
|
||||
}
|
||||
if (this.props.onHeightChange) {
|
||||
this.props.onHeightChange();
|
||||
}
|
||||
if (!this.model.loading.get() && this.wrapperDivRef.current != null) {
|
||||
let height = this.wrapperDivRef.current.offsetHeight;
|
||||
this.updateHeight_debounced(height);
|
||||
}
|
||||
}
|
||||
|
||||
checkRszObs() {
|
||||
if (this.rszObs != null) {
|
||||
return;
|
||||
}
|
||||
if (this.wrapperDivRef.current == null) {
|
||||
return;
|
||||
}
|
||||
this.rszObs = new ResizeObserver(this.handleResize.bind(this));
|
||||
this.rszObs.observe(this.wrapperDivRef.current);
|
||||
checkRszObs() {
|
||||
if (this.rszObs != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.checkRszObs();
|
||||
if (this.wrapperDivRef.current == null) {
|
||||
return;
|
||||
}
|
||||
this.rszObs = new ResizeObserver(this.handleResize.bind(this));
|
||||
this.rszObs.observe(this.wrapperDivRef.current);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
let {rendererContainer, lineId} = this.props;
|
||||
rendererContainer.unloadRenderer(lineId);
|
||||
if (this.rszObs != null) {
|
||||
this.rszObs.disconnect();
|
||||
this.rszObs = null;
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
this.checkRszObs();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.checkRszObs();
|
||||
componentWillUnmount() {
|
||||
let { rendererContainer, lineId } = this.props;
|
||||
rendererContainer.unloadRenderer(lineId);
|
||||
if (this.rszObs != null) {
|
||||
this.rszObs.disconnect();
|
||||
this.rszObs = null;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let {plugin} = this.props;
|
||||
let model = this.model;
|
||||
if (model.loading.get()) {
|
||||
let height = this.model.savedHeight;
|
||||
return (<div ref={this.wrapperDivRef} style={{minHeight: height}}>...</div>);
|
||||
}
|
||||
let Comp = plugin.simpleComponent;
|
||||
if (Comp == null) {
|
||||
<div ref={this.wrapperDivRef}>
|
||||
(no component found in plugin)
|
||||
</div>
|
||||
}
|
||||
let dataBlob = new Blob([model.ptyData.data]);
|
||||
let simpleModel = (model as SimpleBlobRendererModel);
|
||||
return (
|
||||
<div ref={this.wrapperDivRef}>
|
||||
<Comp data={dataBlob} context={simpleModel.context} opts={simpleModel.opts} savedHeight={simpleModel.savedHeight}/>
|
||||
</div>
|
||||
);
|
||||
componentDidUpdate() {
|
||||
this.checkRszObs();
|
||||
}
|
||||
|
||||
render() {
|
||||
let { plugin } = this.props;
|
||||
let model = this.model;
|
||||
if (model.loading.get()) {
|
||||
let height = this.model.savedHeight;
|
||||
return (
|
||||
<div ref={this.wrapperDivRef} style={{ minHeight: height }}>
|
||||
...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
let Comp = plugin.simpleComponent;
|
||||
if (Comp == null) {
|
||||
<div ref={this.wrapperDivRef}>(no component found in plugin)</div>;
|
||||
}
|
||||
let dataBlob = new Blob([model.ptyData.data]);
|
||||
let simpleModel = model as SimpleBlobRendererModel;
|
||||
let { festate, cmdstr } = this.props.initParams.rawCmd;
|
||||
return (
|
||||
<div ref={this.wrapperDivRef}>
|
||||
<Comp
|
||||
cwd={festate.cwd}
|
||||
cmdstr={cmdstr}
|
||||
data={dataBlob}
|
||||
context={simpleModel.context}
|
||||
opts={simpleModel.opts}
|
||||
savedHeight={simpleModel.savedHeight}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export {SimpleBlobRendererModel, SimpleBlobRenderer};
|
||||
|
||||
export { SimpleBlobRendererModel, SimpleBlobRenderer };
|
||||
|
||||
+479
-400
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,95 @@
|
||||
import * as React from "react";
|
||||
import * as mobx from "mobx";
|
||||
import * as mobxReact from "mobx-react";
|
||||
import { RendererContext, RendererOpts } from "../types";
|
||||
import Editor from "@monaco-editor/react";
|
||||
|
||||
/**
|
||||
* Note: As mentioned in https://www.npmjs.com/package/@monaco-editor/react#for-electron-users,
|
||||
* Monaco gets loaded from CDN. This may be problematic if we are behind a firewall etc. If this happens,
|
||||
* We need to serve Monaco from node_modules instead
|
||||
*/
|
||||
|
||||
type OV<V> = mobx.IObservableValue<V>;
|
||||
|
||||
const MaxJsonSize = 50000;
|
||||
|
||||
@mobxReact.observer
|
||||
class SourceCodeRenderer extends React.Component<
|
||||
{
|
||||
data: Blob;
|
||||
path: String;
|
||||
context: RendererContext;
|
||||
opts: RendererOpts;
|
||||
savedHeight: number;
|
||||
},
|
||||
{}
|
||||
> {
|
||||
code: OV<any> = mobx.observable.box(null, {
|
||||
name: "code",
|
||||
deep: false,
|
||||
});
|
||||
language: OV<any> = mobx.observable.box(null, {
|
||||
name: "language",
|
||||
deep: false,
|
||||
});
|
||||
|
||||
editorRef;
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.editorRef = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let prtn = this.props.data.text();
|
||||
prtn.then((text) => this.code.set(text));
|
||||
}
|
||||
|
||||
handleEditorDidMount = (editor, monaco) => {
|
||||
const extension = this.props.cmdstr.split(".").pop();
|
||||
const detectedLanguage = monaco.languages
|
||||
.getLanguages()
|
||||
.find(
|
||||
(lang) => lang.extensions && lang.extensions.includes("." + extension)
|
||||
);
|
||||
if (detectedLanguage) {
|
||||
this.editorRef.current = editor;
|
||||
const model = editor.getModel();
|
||||
if (model) {
|
||||
monaco.editor.setModelLanguage(model, detectedLanguage.id);
|
||||
this.language.set(detectedLanguage.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
let opts = this.props.opts;
|
||||
let maxWidth = opts.maxSize.width;
|
||||
let minWidth = opts.maxSize.width;
|
||||
if (minWidth > 1000) {
|
||||
minWidth = 1000;
|
||||
}
|
||||
let lang = this.language.get();
|
||||
let code = this.code.get();
|
||||
if (!code) return <></>;
|
||||
return (
|
||||
<div className="renderer-container code-renderer">
|
||||
<div className="scroller" style={{ maxHeight: opts.maxSize.height }}>
|
||||
<Editor
|
||||
height="30vh"
|
||||
theme="hc-black"
|
||||
defaultLanguage={lang}
|
||||
defaultValue={code}
|
||||
onMount={this.handleEditorDidMount}
|
||||
options={{
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: "14px",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { SourceCodeRenderer };
|
||||
@@ -1594,6 +1594,20 @@
|
||||
dependencies:
|
||||
cross-spawn "^7.0.1"
|
||||
|
||||
"@monaco-editor/loader@^1.3.3":
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.3.3.tgz#7f1742bd3cc21c0362a46a4056317f6e5215cfca"
|
||||
integrity sha512-6KKF4CTzcJiS8BJwtxtfyYt9shBiEv32ateQ9T4UVogwn4HM/uPo9iJd2Dmbkpz8CM6Y0PDUpjnZzCwC+eYo2Q==
|
||||
dependencies:
|
||||
state-local "^1.0.6"
|
||||
|
||||
"@monaco-editor/react@^4.5.1":
|
||||
version "4.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@monaco-editor/react/-/react-4.5.1.tgz#fbc76c692aee9a33b9ab24ae0c5f219b8f002fdb"
|
||||
integrity sha512-NNDFdP+2HojtNhCkRfE6/D6ro6pBNihaOzMbGK84lNWzRu+CfBjwzGt4jmnqimLuqp5yE5viHS2vi+QOAnD5FQ==
|
||||
dependencies:
|
||||
"@monaco-editor/loader" "^1.3.3"
|
||||
|
||||
"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3":
|
||||
version "2.1.8-no-fsevents.3"
|
||||
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b"
|
||||
@@ -7064,6 +7078,11 @@ stack-trace@0.0.x:
|
||||
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
|
||||
integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==
|
||||
|
||||
state-local@^1.0.6:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/state-local/-/state-local-1.0.7.tgz#da50211d07f05748d53009bee46307a37db386d5"
|
||||
integrity sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==
|
||||
|
||||
statuses@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||
|
||||
Reference in New Issue
Block a user