Moved bold and italics to plug, new file: plug protocol
parent
94d0e31b30
commit
b22775fcc4
|
@ -8,7 +8,7 @@
|
||||||
"clean": "rm -rf .parcel-cache packages/*/dist",
|
"clean": "rm -rf .parcel-cache packages/*/dist",
|
||||||
"build": "parcel build packages/{web,server,plugos}",
|
"build": "parcel build packages/{web,server,plugos}",
|
||||||
"plugs": "cd packages/plugs && npm run watch",
|
"plugs": "cd packages/plugs && npm run watch",
|
||||||
"server": "cd packages/server && npm start",
|
"server": "nodemon -w packages/server/dist --exec 'silverbullet pages'",
|
||||||
"test": "jest packages/*/dist/test",
|
"test": "jest packages/*/dist/test",
|
||||||
"publish-all": "npm publish --access public --ws"
|
"publish-all": "npm publish --access public --ws"
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,6 +17,14 @@ export function getCursor(): Promise<number> {
|
||||||
return syscall("editor.getCursor");
|
return syscall("editor.getCursor");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSelection(): Promise<{ from: number; to: number }> {
|
||||||
|
return syscall("editor.getSelection");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSelection(from: number, to: number): Promise<void> {
|
||||||
|
return syscall("editor.setSelection", from, to);
|
||||||
|
}
|
||||||
|
|
||||||
export function save(): Promise<void> {
|
export function save(): Promise<void> {
|
||||||
return syscall("editor.save");
|
return syscall("editor.save");
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,6 +214,12 @@ function $11a7e2bff790f35a$export$c72d34660a162238() {
|
||||||
function $11a7e2bff790f35a$export$da3f040fb23d21f() {
|
function $11a7e2bff790f35a$export$da3f040fb23d21f() {
|
||||||
return $4ba3510c824e3aea$export$c5be9092dbf465c("editor.getCursor");
|
return $4ba3510c824e3aea$export$c5be9092dbf465c("editor.getCursor");
|
||||||
}
|
}
|
||||||
|
function $11a7e2bff790f35a$export$ca798a7e6e94638c() {
|
||||||
|
return $4ba3510c824e3aea$export$c5be9092dbf465c("editor.getSelection");
|
||||||
|
}
|
||||||
|
function $11a7e2bff790f35a$export$f6e36f80a8190133(from, to) {
|
||||||
|
return $4ba3510c824e3aea$export$c5be9092dbf465c("editor.setSelection", from, to);
|
||||||
|
}
|
||||||
function $11a7e2bff790f35a$export$a1544dad697b423d() {
|
function $11a7e2bff790f35a$export$a1544dad697b423d() {
|
||||||
return $4ba3510c824e3aea$export$c5be9092dbf465c("editor.save");
|
return $4ba3510c824e3aea$export$c5be9092dbf465c("editor.save");
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -132,3 +132,22 @@ functions:
|
||||||
path: ./template.ts:instantiateTemplateCommand
|
path: ./template.ts:instantiateTemplateCommand
|
||||||
command:
|
command:
|
||||||
name: "Template: Instantiate for Page"
|
name: "Template: Instantiate for Page"
|
||||||
|
|
||||||
|
quoteSelection:
|
||||||
|
path: ./text.ts:quoteSelection
|
||||||
|
command:
|
||||||
|
name: "Text: Quote Selection"
|
||||||
|
key: "Ctrl->"
|
||||||
|
mac: "Cmd-Shift-."
|
||||||
|
bold:
|
||||||
|
path: ./text.ts:boldCommand
|
||||||
|
command:
|
||||||
|
name: "Text: Bold"
|
||||||
|
key: "Ctrl-b"
|
||||||
|
mac: "Cmd-b"
|
||||||
|
italic:
|
||||||
|
path: ./text.ts:italicCommand
|
||||||
|
command:
|
||||||
|
name: "Text: Italic"
|
||||||
|
key: "Ctrl-i"
|
||||||
|
mac: "Cmd-i"
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
import {
|
||||||
|
getSelection,
|
||||||
|
getText,
|
||||||
|
insertAtCursor,
|
||||||
|
moveCursor,
|
||||||
|
replaceRange,
|
||||||
|
setSelection,
|
||||||
|
} from "@silverbulletmd/plugos-silverbullet-syscall/editor";
|
||||||
|
|
||||||
|
export async function quoteSelection() {
|
||||||
|
let text = await getText();
|
||||||
|
const selection = await getSelection();
|
||||||
|
let from = selection.from;
|
||||||
|
while (from >= 0 && text[from] !== "\n") {
|
||||||
|
from--;
|
||||||
|
}
|
||||||
|
from++;
|
||||||
|
if (text[from] === ">" && text[from + 1] === " ") {
|
||||||
|
// Already quoted, we have to unquote
|
||||||
|
text = text.slice(from + 2, selection.to);
|
||||||
|
text = text.replaceAll("\n> ", "\n");
|
||||||
|
} else {
|
||||||
|
text = text.slice(from, selection.to);
|
||||||
|
text = `> ${text.replaceAll("\n", "\n> ")}`;
|
||||||
|
}
|
||||||
|
await replaceRange(from, selection.to, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function boldCommand() {
|
||||||
|
return insertMarker("**");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function italicCommand() {
|
||||||
|
return insertMarker("_");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertMarker(marker: string) {
|
||||||
|
let text = await getText();
|
||||||
|
const selection = await getSelection();
|
||||||
|
if (selection.from === selection.to) {
|
||||||
|
// empty selection
|
||||||
|
if (markerAt(selection.from)) {
|
||||||
|
// Already there, skipping ahead
|
||||||
|
await moveCursor(selection.from + marker.length);
|
||||||
|
} else {
|
||||||
|
// Not there, inserting
|
||||||
|
await insertAtCursor(marker + marker);
|
||||||
|
await moveCursor(selection.from + marker.length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let from = selection.from;
|
||||||
|
let to = selection.to;
|
||||||
|
let hasMarker = markerAt(from);
|
||||||
|
if (!markerAt(from)) {
|
||||||
|
// Maybe just before the cursor? We'll accept that
|
||||||
|
from = selection.from - marker.length;
|
||||||
|
to = selection.to + marker.length;
|
||||||
|
hasMarker = markerAt(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasMarker) {
|
||||||
|
// Adding
|
||||||
|
await replaceRange(
|
||||||
|
selection.from,
|
||||||
|
selection.to,
|
||||||
|
marker + text.slice(selection.from, selection.to) + marker
|
||||||
|
);
|
||||||
|
await setSelection(
|
||||||
|
selection.from + marker.length,
|
||||||
|
selection.to + marker.length
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Removing
|
||||||
|
await replaceRange(
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
text.substring(from + marker.length, to - marker.length)
|
||||||
|
);
|
||||||
|
await setSelection(from, to - marker.length * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function markerAt(pos: number) {
|
||||||
|
for (var i = 0; i < marker.length; i++) {
|
||||||
|
if (text[pos + i] !== marker[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -134,7 +134,6 @@ export class ExpressServer {
|
||||||
this.eventHook.addLocalListener(
|
this.eventHook.addLocalListener(
|
||||||
"get-plug:builtin",
|
"get-plug:builtin",
|
||||||
async (plugName: string): Promise<Manifest> => {
|
async (plugName: string): Promise<Manifest> => {
|
||||||
// console.log("Ok, resovling a plugin", plugName);
|
|
||||||
if (!safeFilename.test(plugName)) {
|
if (!safeFilename.test(plugName)) {
|
||||||
throw new Error(`Invalid plug name: ${plugName}`);
|
throw new Error(`Invalid plug name: ${plugName}`);
|
||||||
}
|
}
|
||||||
|
@ -150,6 +149,26 @@ export class ExpressServer {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.eventHook.addLocalListener(
|
||||||
|
"get-plug:file",
|
||||||
|
async (plugPath: string): Promise<Manifest> => {
|
||||||
|
let resolvedPath = path.resolve(plugPath);
|
||||||
|
if (!resolvedPath.startsWith(process.cwd())) {
|
||||||
|
throw new Error(
|
||||||
|
`Plugin path outside working directory, this is disallowed: ${resolvedPath}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
let manifestJson = await readFile(resolvedPath, "utf8");
|
||||||
|
return JSON.parse(manifestJson);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(
|
||||||
|
`No such file: ${resolvedPath} or could not parse as JSON`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
this.space.updatePageList().catch(console.error);
|
this.space.updatePageList().catch(console.error);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
"silverbullet": "./dist/server/server.js"
|
"silverbullet": "./dist/server/server.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "nodemon -w dist --exec 'silverbullet ../../pages'",
|
|
||||||
"test": "jest dist/test"
|
"test": "jest dist/test"
|
||||||
},
|
},
|
||||||
"targets": {
|
"targets": {
|
||||||
|
|
|
@ -373,16 +373,6 @@ export class Editor {
|
||||||
...completionKeymap,
|
...completionKeymap,
|
||||||
indentWithTab,
|
indentWithTab,
|
||||||
...commandKeyBindings,
|
...commandKeyBindings,
|
||||||
{
|
|
||||||
key: "Ctrl-b",
|
|
||||||
mac: "Cmd-b",
|
|
||||||
run: commands.insertMarker("**"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "Ctrl-i",
|
|
||||||
mac: "Cmd-i",
|
|
||||||
run: commands.insertMarker("_"),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: "Ctrl-k",
|
key: "Ctrl-k",
|
||||||
mac: "Cmd-k",
|
mac: "Cmd-k",
|
||||||
|
@ -612,7 +602,7 @@ export class Editor {
|
||||||
this.viewState = viewState;
|
this.viewState = viewState;
|
||||||
this.viewDispatch = dispatch;
|
this.viewDispatch = dispatch;
|
||||||
|
|
||||||
let editor = this;
|
const editor = this;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (viewState.currentPage) {
|
if (viewState.currentPage) {
|
||||||
|
@ -641,7 +631,7 @@ export class Editor {
|
||||||
<CommandPalette
|
<CommandPalette
|
||||||
onTrigger={(cmd) => {
|
onTrigger={(cmd) => {
|
||||||
dispatch({ type: "hide-palette" });
|
dispatch({ type: "hide-palette" });
|
||||||
editor!.focus();
|
editor.focus();
|
||||||
if (cmd) {
|
if (cmd) {
|
||||||
dispatch({ type: "command-run", command: cmd.command.name });
|
dispatch({ type: "command-run", command: cmd.command.name });
|
||||||
cmd.run().catch((e) => {
|
cmd.run().catch((e) => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Editor } from "../editor";
|
import { Editor } from "../editor";
|
||||||
import { Transaction } from "@codemirror/state";
|
import { SelectionRange, Transaction } from "@codemirror/state";
|
||||||
import { SysCallMapping } from "@plugos/plugos/system";
|
import { SysCallMapping } from "@plugos/plugos/system";
|
||||||
import { FilterOption } from "@silverbulletmd/common/types";
|
import { FilterOption } from "@silverbulletmd/common/types";
|
||||||
|
|
||||||
|
@ -37,6 +37,9 @@ export function editorSyscalls(editor: Editor): SysCallMapping {
|
||||||
"editor.getCursor": (): number => {
|
"editor.getCursor": (): number => {
|
||||||
return editor.editorView!.state.selection.main.from;
|
return editor.editorView!.state.selection.main.from;
|
||||||
},
|
},
|
||||||
|
"editor.getSelection": (): { from: number; to: number } => {
|
||||||
|
return editor.editorView!.state.selection.main;
|
||||||
|
},
|
||||||
"editor.save": async () => {
|
"editor.save": async () => {
|
||||||
return editor.save(true);
|
return editor.save(true);
|
||||||
},
|
},
|
||||||
|
@ -127,6 +130,16 @@ export function editorSyscalls(editor: Editor): SysCallMapping {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
"editor.setSelection": (ctx, from: number, to: number) => {
|
||||||
|
let editorView = editor.editorView!;
|
||||||
|
editorView.dispatch({
|
||||||
|
selection: {
|
||||||
|
anchor: from,
|
||||||
|
head: to,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
"editor.insertAtCursor": (ctx, text: string) => {
|
"editor.insertAtCursor": (ctx, text: string) => {
|
||||||
let editorView = editor.editorView!;
|
let editorView = editor.editorView!;
|
||||||
let from = editorView.state.selection.main.from;
|
let from = editorView.state.selection.main.from;
|
||||||
|
|
Loading…
Reference in New Issue