Antedit v0.2.0

- fix compatible bug with new Monaco version
- the editor now can support diff view of two files
This commit is contained in:
lxsang 2022-07-04 18:11:05 +02:00
parent 21f2e58768
commit c994d1c738
10 changed files with 268 additions and 50 deletions

View File

@ -6,6 +6,7 @@ The editor functionality can be extended by its extension mechanism.
Extension can be developed/released/isntalled by the editor itself.
### Change logs
- 0.2.0-b: Support diff mode in editor + fix new Monaco version compatible bug
- 0.1.17-b: Fix extension keybinding bug with the new monaco editor
- 0.1.16-b: use the new version of monaco editor
- 0.1.14-b: improve output log display

View File

@ -6,6 +6,7 @@ The editor functionality can be extended by its extension mechanism.
Extension can be developed/released/isntalled by the editor itself.
### Change logs
- 0.2.0-b: Support diff mode in editor + fix new Monaco version compatible bug
- 0.1.17-b: Fix extension keybinding bug with the new monaco editor
- 0.1.16-b: use the new version of monaco editor
- 0.1.14-b: improve output log display

File diff suppressed because one or more lines are too long

View File

@ -7,7 +7,7 @@
"author": "Xuan Sang LE",
"email": "mrsang@iohub.dev"
},
"version": "0.1.17-b",
"version": "0.2.0-b",
"category": "Development",
"iconclass": "bi bi-journal-code",
"mimes": [

Binary file not shown.

View File

@ -7,7 +7,7 @@
"author": "Xuan Sang LE",
"email": "mrsang@iohub.dev"
},
"version": "0.1.17-b",
"version": "0.2.0-b",
"category": "Development",
"iconclass": "bi bi-journal-code",
"mimes": [

View File

@ -1,12 +1,90 @@
namespace OS {
//declare var $:any;
export namespace API
{
export namespace VFS
{
export class DiffEditorFileHandle extends OS.API.VFS.BaseFileHandle
{
text: string;
textModel:any;
selected: boolean;
constructor(files: OS.API.VFS.BaseFileHandle[]) {
super("");
this.path = `${files[0].path} -> ${files[1].path}`;
this.cache = files;
this.basename = `${files[0].basename} -> ${files[1].basename}`;
this.info = {
type: "file",
mime: undefined,
size: 0,
name: this.basename,
path: this.path
};
this.ready = true;
}
meta(): Promise<any> {
return new Promise(async (resolve, reject) =>
{
try
{
await Promise.all([this.cache[0].meta(), this.cache[1].meta]);
resolve({
result: this.info,
error: false,
});
}
catch(e)
{
reject(e);
}
});
}
protected _rd(_t: string): Promise<any> {
return new Promise(async (resolve, reject) => {
try
{
this.cache[0].cache = await this.cache[0].read();
this.cache[1].cache = await this.cache[1].read();
resolve(this.cache);
}
catch(e)
{
reject(e);
}
});
}
protected _wr(t: string, d: any): Promise<any> {
this.cache = d;
return new Promise((resolve, reject) =>
{
resolve({
result: true,
error: false,
})
});
}
setPath(s: string)
{
// do nothing
}
}
}
}
export namespace application {
/**
* Extends the [[RemoteFileHandle]] interface with some useful
* properties used by [[BaseEditorModel]]
*/
export type EditorFileHandle = API.VFS.RemoteFileHandle & {
export type EditorFileHandle = OS.API.VFS.BaseFileHandle & {
/**
* The text will be displayed on the tab bar when opened
*
@ -81,7 +159,7 @@ namespace OS {
* @type {boolean}
* @memberof BaseEditorModel
*/
private editormux: boolean;
//private editormux: boolean;
/**
@ -98,7 +176,7 @@ namespace OS {
this.tabbar = tabbar;
this.editorSetup(editorarea);
this.app = app;
this.editormux = false;
// this.editormux = false;
this.onstatuschange = undefined;
this.on("focus", () => {
@ -106,11 +184,14 @@ namespace OS {
this.onstatuschange(this.getEditorStatus());
});
this.on("input", () => {
if (this.editormux) {
// console.log(this.editormux, this.currfile.dirty);
/*if (this.editormux) {
this.editormux = false;
console.log("set editor mux to false");
return false;
}
}*/
if (!this.currfile.dirty) {
console.log("dirty", this.currfile.path);
this.currfile.dirty = true;
this.currfile.text += "*";
return this.tabbar.update(undefined);
@ -232,10 +313,8 @@ namespace OS {
this.currfile = file;
}
this.editormux = true;
// this.editormux = true;
this.setTextModel(file.textModel);
if (this.onstatuschange)
this.onstatuschange(this.getEditorStatus());
this.focus();
}
@ -274,7 +353,6 @@ namespace OS {
this.newTab(file);
return;
}
file.read()
.then((d) => {
file.cache = d || "";
@ -295,16 +373,16 @@ namespace OS {
* @param {EditorFileHandle} file
* @memberof BaseEditorModel
*/
private write(file: EditorFileHandle): void {
private write(): void {
this.currfile.cache = this.getValue();
file.write("text/plain")
this.currfile.write("text/plain")
.then((d) => {
file.dirty = false;
file.text = file.basename;
this.currfile.dirty = false;
this.currfile.text = this.currfile.basename;
this.tabbar.update(undefined);
})
.catch((e) =>
this.app.error(__("Unable to save file: {0}", file.path), e)
this.app.error(__("Unable to save file: {0}", this.currfile.path), e)
);
}
@ -318,7 +396,7 @@ namespace OS {
save(): void {
this.currfile.cache = this.getValue();
if (this.currfile.basename) {
return this.write(this.currfile);
return this.write();
}
return this.saveAs();
}
@ -339,7 +417,7 @@ namespace OS {
d = d.parent();
}
this.currfile.setPath(`${d.path}/${f.name}`);
this.write(this.currfile);
this.write();
});
}
@ -376,6 +454,7 @@ namespace OS {
*/
closeAll(): void {
this.tabbar.items = [];
this.openFile("Untitled".asFileHandle() as EditorFileHandle);
this.resetEditor();
}

View File

@ -30,8 +30,6 @@ namespace OS {
* @memberof MonacoEditorModel
*/
protected resetEditor(): void {
this.setValue("");
// TODO create new textmodel
}
@ -76,20 +74,32 @@ namespace OS {
* @memberof MonacoEditorModel
*/
protected newTextModelFrom(file: EditorFileHandle): any {
if(file.path.toString() === "Untitled") {
if(Array.isArray(file.cache))
{
return {
model: monaco.editor.createModel(file.cache, "textplain")
model: {
original: this.newTextModelFrom(file.cache[0]).model,
modified: this.newTextModelFrom(file.cache[1]).model
}
}
}
const uri = monaco.Uri.parse(file.protocol + "://antedit/file/" + file.genealogy.join("/"));
const model = monaco.editor.getModel(uri);
if(model)
else
{
model.setValue(file.cache);
return { model: model };
}
return {
model: monaco.editor.createModel(file.cache, undefined, uri)
if(file.path.toString() === "Untitled") {
return {
model: monaco.editor.createModel(file.cache, "textplain")
}
}
const uri = monaco.Uri.parse(file.protocol + "://antedit/file/" + file.genealogy.join("/"));
const model = monaco.editor.getModel(uri);
if(model)
{
model.setValue(file.cache);
return { model: model };
}
return {
model: monaco.editor.createModel(file.cache, undefined, uri)
}
}
}
@ -103,7 +113,11 @@ namespace OS {
//const list = [];
//return list;
return monaco.languages.getLanguages().map(e=>{
(e as GenericObject<any>).text = e.aliases[0];
const item = (e as GenericObject<any>);
if(e.aliases)
item.text = e.aliases[0];
else
item.text = e.id;
return e;
});
}
@ -134,12 +148,24 @@ namespace OS {
* @memberof MonacoEditorModel
*/
setMode(m: GenericObject<any>): void {
monaco.editor.setModelLanguage(this.editor.getModel(), m.id);
if(this.editor == this._code_editor)
{
monaco.editor.setModelLanguage(this.editor.getModel(), m.id);
}
else
{
for(const model of this.editor.getModel())
{
monaco.editor.setModelLanguage(model, m.id);
}
}
if(this.onstatuschange)
this.onstatuschange(this.getEditorStatus());
}
private code_container: JQuery<HTMLElement>;
private diff_container: JQuery<HTMLElement>;
/**
* Reference to the editor instance
@ -148,7 +174,30 @@ namespace OS {
* @type {GenericObject<any>}
* @memberof MonacoEditorModel
*/
private editor: GenericObject<any>;
private _code_editor: GenericObject<any>;
/**
* Reference to the diff editor instance
*
* @private
* @type {GenericObject<any>}
* @memberof MonacoEditorModel
*/
private _diff_editor: GenericObject<any>;
/**
* Getter get current editor instance based on current file
*
* @private
* @type {GenericObject<any>}
* @memberof MonacoEditorModel
*/
private get editor(): GenericObject<any>
{
if(Array.isArray(this.currfile.cache))
{
return this._diff_editor;
}
return this._code_editor;
}
/**
@ -159,10 +208,24 @@ namespace OS {
* @memberof MonacoEditorModel
*/
protected editorSetup(el: HTMLElement): void {
this.editor = monaco.editor.create(el, {
// create two editor instancs for code mode and diff mode
this.code_container = $("<div />")
.css("width", "100%")
.css("height", "100%");
this.diff_container = $("<div />")
.css("width", "100%")
.css("height", "100%")
.css("display", "none");
$(el).append(this.code_container);
$(el).append(this.diff_container);
this._code_editor = monaco.editor.create(this.code_container[0], {
value: "",
language: 'textplain'
});
this._diff_editor = monaco.editor.createDiffEditor(this.diff_container[0],{
readOnly: true
});
if(!MonacoEditorModel.modes)
{
MonacoEditorModel.modes = {};
@ -183,13 +246,17 @@ namespace OS {
on(evt_str: string, callback: () => void): void {
switch (evt_str) {
case "input":
this.editor.onDidChangeModelContent(callback);
this._code_editor.onDidChangeModelContent(callback);
break;
case "focus":
this.editor.onDidFocusEditorText(callback);
this._code_editor.onDidFocusEditorText(callback);
this._diff_editor.getOriginalEditor().onDidFocusEditorText(callback);
this._diff_editor.getModifiedEditor().onDidFocusEditorText(callback);
break;
case "changeCursor":
this.editor.onDidChangeCursorPosition(callback);
this._code_editor.onDidChangeCursorPosition(callback);
this._diff_editor.getOriginalEditor().onDidChangeCursorPosition(callback);
this._diff_editor.getModifiedEditor().onDidChangeCursorPosition(callback);
break;
default:
break;
@ -214,8 +281,21 @@ namespace OS {
* @memberof MonacoEditorModel
*/
focus(): void {
if(Array.isArray(this.currfile.cache))
{
this.code_container.hide();
this.diff_container.show();
}
else
{
this.code_container.show();
this.diff_container.hide();
}
if(this.editor)
{
this.editor.layout();
this.editor.focus();
}
}
@ -238,14 +318,34 @@ namespace OS {
* @memberof MonacoEditorModel
*/
getEditorStatus(): GenericObject<any> {
const pos = this.editor.getPosition();
const mode = MonacoEditorModel.modes[this.editor.getModel().getLanguageId()];
let ed = undefined;
if(this.editor == this._code_editor)
{
ed = this.editor;
}
else
{
ed = this.editor.getOriginalEditor();
if(this.editor.getModifiedEditor().hasTextFocus())
{
ed = this.editor.getModifiedEditor();
}
}
const pos = ed.getPosition();
let mode = undefined;
const model = ed.getModel();
if(model)
{
mode = MonacoEditorModel.modes[model.getLanguageId()];
}
return {
row: pos.lineNumber,
column: pos.column,
line: this.editor.getModel().getLineCount(),
line: model?model.getLineCount(): 0,
langmode: {
text: mode.aliases[0],
text: mode?mode.aliases[0]: "",
mode: mode
},
file: this.currfile.path
@ -260,7 +360,9 @@ namespace OS {
* @memberof MonacoEditorModel
*/
getValue(): string {
return this.editor.getValue();
if(this.editor == this._code_editor)
return this.editor.getValue();
return this.currfile.cache;
}
@ -271,7 +373,8 @@ namespace OS {
* @memberof MonacoEditorModel
*/
setValue(value: string): void {
this.editor.setValue(value);
if(this.editor == this._code_editor)
this.editor.setValue(value);
}
getEditor(): any {

View File

@ -235,6 +235,15 @@ namespace OS {
*/
private split_mode: boolean;
/**
* Buffer for open diff
*
* @private
* @type {EditorFileHandle[]}
* @memberof Antedit
*/
private diff_buffer: EditorFileHandle[];
/**
* Reference to the editor logger
*
@ -270,6 +279,7 @@ namespace OS {
constructor(args: AppArgumentsType[]) {
super("Antedit", args);
this.currdir = undefined;
this.diff_buffer = [undefined, undefined];
}
/**
@ -374,7 +384,6 @@ namespace OS {
break;
case "close-all":
model.closeAll();
model.openFile("Untitled".asFileHandle() as EditorFileHandle)
break;
case "mv-side":
if(!tab)
@ -435,13 +444,21 @@ namespace OS {
this.on("focus", () => this.eum.active.focus());
this.fileview.contextmenuHandle = (e, m) => {
m.items = [
let file: API.VFS.BaseFileHandle | API.FileInfoType = this
.fileview.selectedFile;
const items = [
{ text: "__(New file)", id: "new" },
{ text: "__(New folder)", id: "newdir" },
{ text: "__(Rename)", id: "rename" },
{ text: "__(Delete)", id: "delete" },
{ text: "__(Upload)", id: "upload" },
];
if(file && file.type === "file")
{
items.push( { text: "__(Select for compare)", id: "diff-org" });
items.push( { text: "__(Compare with selected)", id: "diff-mod" });
}
m.items = items;
m.onmenuselect = (e) => {
return this.ctxFileMenuHandle(e);
};
@ -512,6 +529,7 @@ namespace OS {
this.eum.addAction(extension, action, async (e) =>
{
try{
const data = await this.openDialog("SelectionDialog", {
"title": __("Select language"),
data: this.eum.active.getModes()
@ -519,7 +537,7 @@ namespace OS {
this.eum.active.setMode(data);
}catch(e)
{
console.log(e);
}
});
$(this.find("txt_ext_search")).keyup((e) => this.extension_search(e));
@ -687,6 +705,12 @@ namespace OS {
this.bottombar.selectedIndex = 0;
}
openDiff(files: EditorFileHandle[])
{
const diff_file = new API.VFS.DiffEditorFileHandle(files);
this.eum.active.openFile(diff_file as EditorFileHandle);
}
/**
* Apply [[showBottomBar]] from user setting value
*
@ -953,6 +977,16 @@ namespace OS {
})
.catch((e) => this.error(__("Unable to upload file: {e}", e.toString()), __e(e)));
break;
case "diff-org":
if(!file) return;
this.diff_buffer[0] = file.path.asFileHandle() as EditorFileHandle;
break;
case "diff-mod":
if(!file) return;
if(!this.diff_buffer[0]) return;
this.diff_buffer[1] = file.path.asFileHandle() as EditorFileHandle;
this.openDiff(this.diff_buffer);
break;
default:
}
}

View File

@ -45,7 +45,7 @@
"description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Antedit/README.md",
"category": "Development",
"author": "Xuan Sang LE",
"version": "0.1.17-b",
"version": "0.2.0-b",
"dependencies": ["MonacoCore@0.33.0-r"],
"download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Antedit/build/release/Antedit.zip"
},