Skip to content

Instantly share code, notes, and snippets.

@Rishabh-malhotraa
Created February 22, 2021 12:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rishabh-malhotraa/d77fded610f5d581bc2d33be553309b3 to your computer and use it in GitHub Desktop.
Save Rishabh-malhotraa/d77fded610f5d581bc2d33be553309b3 to your computer and use it in GitHub Desktop.
Ace-Bind
import { RealTimeElement, ModelReference } from "@convergence/convergence";
import {
AceMultiCursorManager,
AceMultiSelectionManager,
} from "@convergencelabs/ace-collab-ext";
import AceEditor from "react-ace";
import { Range as AceRange } from "ace-builds";
import { ColorAssigner } from "@convergence/color-assigner";
import { IAceEditor } from "react-ace/lib/types";
type AceEditorInstance = React.RefObject<AceEditor>;
export const initModel = (
textModel: RealTimeElement<string>,
AceEditorRef: AceEditorInstance,
suppressEvents = false
) => {
const editor = AceEditorRef.current!.editor;
console.log("intiModel");
console.log(editor);
const session = editor.getSession();
const document = session.getDocument();
session.setValue(textModel.value());
textModel.on("insert", (e: Record<string, any>) => {
const pos = document.indexToPosition(e.index, 0);
suppressEvents = true;
document.insert(pos, e.value);
suppressEvents = false;
});
textModel.on("remove", (e: Record<string, any>) => {
const start = document.indexToPosition(e.index, 0);
const end = document.indexToPosition(e.index + e.value.length, 0);
suppressEvents = true;
document.remove(new AceRange(start.row, start.column, end.row, end.column));
suppressEvents = false;
});
textModel.on("value", function (e: Record<string, any>) {
suppressEvents = true;
document.setValue(e.value);
suppressEvents = false;
});
editor.on("change", (delta) => {
if (suppressEvents) {
return;
}
const pos = document.positionToIndex(delta.start);
switch (delta.action) {
case "insert":
//@ts-ignore
textModel.insert(pos, delta.lines.join("\n"));
break;
case "remove":
//@ts-ignore
textModel.remove(pos, delta.lines.join("\n").length);
break;
default:
throw new Error("unknown action: " + delta.action);
}
});
};
/////////////////////////////////////////////////////////////////////////////
// Cursor Binding
/////////////////////////////////////////////////////////////////////////////
export const initSharedCursors = (
textModel: RealTimeElement<string>,
editor: IAceEditor,
suppressEvents = false,
cursorKey = "cursor"
) => {
console.log("insidde initSharedCursor");
console.log(editor);
const session = editor.getSession();
const document = session.getDocument();
const cursorManager = new AceMultiCursorManager(editor.getSession());
//@ts-ignore
const cursorReference = textModel.indexReference(cursorKey);
console.log(cursorReference);
const references = textModel.references({ key: cursorKey });
references.forEach((reference) => {
if (!reference.isLocal()) {
addCursor(editor, reference, cursorManager);
}
});
setLocalCursor(editor, cursorReference);
cursorReference.share();
editor
.getSession()
.selection.on("changeCursor", () => setLocalCursor(editor, document));
textModel.on("reference", (e: Record<string, any>) => {
if (e.reference.key() === cursorKey) {
addCursor(editor, e.reference, cursorManager);
}
});
};
function setLocalCursor(editor: IAceEditor, cursorReference: any) {
const position = editor.getCursorPosition();
const document = editor.getSession().getDocument();
const index = document.positionToIndex(position);
cursorReference.set(index);
}
function addCursor(
editor: IAceEditor,
reference: ModelReference<any>,
cursorManager: AceMultiCursorManager
) {
const colorAssigner = new ColorAssigner(ColorAssigner.Palettes.LIGHT_12);
const color = colorAssigner.getColorAsHex(reference.sessionId());
const remoteCursorIndex = reference.value();
cursorManager.addCursor(
reference.sessionId(),
"user-name",
color,
remoteCursorIndex
);
reference.on("cleared", () =>
cursorManager.clearCursor(reference.sessionId())
);
reference.on("disposed", () =>
cursorManager.removeCursor(reference.sessionId())
);
reference.on("set", () => {
const cursorIndex = reference.value();
cursorManager.setCursor(reference.sessionId(), cursorIndex);
// check alert for 0 shizz
// const document = editor.getSession().getDocument();
// const cursorRow = document.indexToPosition(cursorIndex, 0).row;
// if (radarView.hasView(reference.sessionId())) {
// radarView.setCursorRow(reference.sessionId(), cursorRow);
// }
});
}
/////////////////////////////////////////////////////////////////////////////
// Selection Binding
/////////////////////////////////////////////////////////////////////////////
export const initSharedSelection = (
textModel: RealTimeElement<any>,
AceEditorRef: AceEditorInstance,
suppressEvents = false,
selectionKey = "selection"
) => {
const editor = AceEditorRef.current!.editor;
const session = editor.getSession();
console.log(editor);
const selectionManager = new AceMultiSelectionManager(editor.getSession());
//@ts-ignore The type definations could be improved URGHHHH
const selectionReference = textModel.rangeReference(selectionKey);
setLocalSelection(editor, selectionReference);
selectionReference.share();
session.selection.on("changeSelection", () =>
setLocalSelection(editor, selectionReference)
);
const references = textModel.references({ key: selectionKey });
references.forEach((reference) => {
if (!reference.isLocal()) {
addSelection(editor, reference, selectionManager);
}
});
textModel.on("reference", (e: Record<string, any>) => {
console.log("textSelection");
console.log(e);
if (e.reference.key() === selectionKey) {
addSelection(editor, e.reference, selectionManager);
}
});
};
function setLocalSelection(editor: IAceEditor, selectionReference: any) {
const document = editor.getSession().getDocument();
if (!editor.selection.isEmpty()) {
const aceRanges = editor.selection.getAllRanges();
const indexRanges = aceRanges.map((aceRagne) => {
const start = document.positionToIndex(aceRagne.start);
const end = document.positionToIndex(aceRagne.end);
return { start: start, end: end };
});
selectionReference.set(indexRanges);
} else if (selectionReference.isSet()) {
selectionReference.clear();
}
}
function addSelection(
editor: IAceEditor,
reference: ModelReference<any>,
selectionManager: AceMultiSelectionManager
) {
const colorAssigner = new ColorAssigner(ColorAssigner.Palettes.LIGHT_12);
const color = colorAssigner.getColorAsHex(reference.sessionId());
const remoteSelection = reference
.values()
.map((range) => toAceRange(editor, range));
selectionManager.addSelection(
reference.sessionId(),
reference.user().username,
color,
//@ts-ignore
remoteSelection
);
reference.on("cleared", () =>
selectionManager.clearSelection(reference.sessionId())
);
reference.on("disposed", () =>
selectionManager.removeSelection(reference.sessionId())
);
reference.on("set", () => {
selectionManager.setSelection(
reference.sessionId(),
//@ts-ignore
reference.values().map((range) => toAceRange(editor, range))
);
});
}
function toAceRange(editor: IAceEditor, range: Record<string, number>) {
if (typeof range !== "object") {
return null;
}
let start = range.start;
let end = range.end;
if (start > end) {
const temp = start;
start = end;
end = temp;
}
const document = editor.getSession().getDocument();
const rangeAnchor = document.indexToPosition(start, 0);
const rangeLead = document.indexToPosition(end, 0);
return new AceRange(
rangeAnchor.row,
rangeAnchor.column,
rangeLead.row,
rangeLead.column
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment