Fixes #643
This commit is contained in:
+8
-2
@@ -10,7 +10,7 @@ import {
|
||||
} from "../common/deps.ts";
|
||||
import { Space } from "./space.ts";
|
||||
import { FilterOption } from "./types.ts";
|
||||
import { ensureSettingsAndIndex } from "../common/util.ts";
|
||||
import { ensureAndLoadSettingsAndIndex } from "../common/util.ts";
|
||||
import { EventHook } from "../plugos/hooks/event.ts";
|
||||
import { AppCommand } from "./hooks/command.ts";
|
||||
import {
|
||||
@@ -242,7 +242,13 @@ export class Client {
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = await ensureSettingsAndIndex(this.space.spacePrimitives);
|
||||
this.settings = await ensureAndLoadSettingsAndIndex(
|
||||
this.space.spacePrimitives,
|
||||
);
|
||||
this.ui.viewDispatch({
|
||||
type: "settings-loaded",
|
||||
settings: this.settings,
|
||||
});
|
||||
}
|
||||
|
||||
private async initSync() {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { commandLinkRegex } from "../../common/markdown_parser/parser.ts";
|
||||
import { ClickEvent } from "$sb/app_event.ts";
|
||||
import { Decoration, syntaxTree } from "../deps.ts";
|
||||
import { Client } from "../client.ts";
|
||||
@@ -8,6 +7,7 @@ import {
|
||||
invisibleDecoration,
|
||||
isCursorInRange,
|
||||
} from "./util.ts";
|
||||
import { commandLinkRegex } from "../../common/command.ts";
|
||||
|
||||
/**
|
||||
* Plugin to hide path prefix when the cursor is not inside.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { isMacLike } from "../../common/util.ts";
|
||||
import { FilterList } from "./filter.tsx";
|
||||
import { CompletionContext, CompletionResult, TerminalIcon } from "../deps.ts";
|
||||
import { CompletionContext, CompletionResult, featherIcons } from "../deps.ts";
|
||||
import { AppCommand } from "../hooks/command.ts";
|
||||
import { BuiltinSettings, FilterOption } from "../types.ts";
|
||||
import { commandLinkRegex } from "../../common/markdown_parser/parser.ts";
|
||||
import { parseCommand } from "../../common/command.ts";
|
||||
|
||||
export function CommandPalette({
|
||||
commands,
|
||||
@@ -25,6 +25,9 @@ export function CommandPalette({
|
||||
const options: FilterOption[] = [];
|
||||
const isMac = isMacLike();
|
||||
for (const [name, def] of commands.entries()) {
|
||||
if (def.command.hide) {
|
||||
continue;
|
||||
}
|
||||
let shortcut: { key?: string; mac?: string; priority?: number } =
|
||||
def.command;
|
||||
// Let's see if there's a shortcut override
|
||||
@@ -32,11 +35,9 @@ export function CommandPalette({
|
||||
const commandOverride = settings.shortcuts.find((
|
||||
shortcut,
|
||||
) => {
|
||||
const commandMatch = commandLinkRegex.exec(shortcut.command);
|
||||
const parsedCommand = parseCommand(shortcut.command);
|
||||
// If this is a command link, we want to match the command name but also make sure no arguments were set
|
||||
return commandMatch && commandMatch[1] === name && !commandMatch[5] ||
|
||||
// or if it's not a command link, let's match exactly
|
||||
shortcut.command === name;
|
||||
return parsedCommand.name === name && parsedCommand.args.length === 0;
|
||||
});
|
||||
if (commandOverride) {
|
||||
shortcut = commandOverride;
|
||||
@@ -58,7 +59,7 @@ export function CommandPalette({
|
||||
placeholder="Command"
|
||||
options={options}
|
||||
allowNew={false}
|
||||
icon={TerminalIcon}
|
||||
icon={featherIcons.Terminal}
|
||||
completer={completer}
|
||||
vimMode={vimMode}
|
||||
darkMode={darkMode}
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
CompletionContext,
|
||||
CompletionResult,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from "../deps.ts";
|
||||
import { CompletionContext, CompletionResult, useEffect } from "../deps.ts";
|
||||
import type { ComponentChildren, FunctionalComponent } from "../deps.ts";
|
||||
import { Notification } from "../types.ts";
|
||||
import { FeatherProps } from "https://esm.sh/v99/preact-feather@4.2.1/dist/types";
|
||||
@@ -65,8 +60,9 @@ export function TopBar({
|
||||
const innerDiv = currentPageElement.parentElement!.parentElement!;
|
||||
|
||||
// Then calculate a new width
|
||||
const substract = 60 + actionButtons.length * 31;
|
||||
currentPageElement.style.width = `${
|
||||
Math.min(editorWidth - 170, innerDiv.clientWidth - 170)
|
||||
Math.min(editorWidth - substract, innerDiv.clientWidth - substract)
|
||||
}px`;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -9,13 +9,7 @@ export {
|
||||
useState,
|
||||
} from "https://esm.sh/preact@10.11.1/hooks";
|
||||
|
||||
export {
|
||||
Book as BookIcon,
|
||||
Home as HomeIcon,
|
||||
RefreshCw as RefreshCwIcon,
|
||||
Terminal as TerminalIcon,
|
||||
Type as TemplateIcon,
|
||||
} from "https://esm.sh/preact-feather@4.2.1?external=preact";
|
||||
export * as featherIcons from "https://esm.sh/preact-feather@4.2.1?external=preact";
|
||||
|
||||
// Vim mode
|
||||
export {
|
||||
|
||||
+13
-17
@@ -1,4 +1,3 @@
|
||||
import { commandLinkRegex } from "../common/markdown_parser/parser.ts";
|
||||
import { readonlyMode } from "./cm_plugins/readonly.ts";
|
||||
import customMarkdownStyle from "./style.ts";
|
||||
import {
|
||||
@@ -45,6 +44,7 @@ import { languageFor } from "../common/languages.ts";
|
||||
import { plugLinter } from "./cm_plugins/lint.ts";
|
||||
import { Compartment, Extension } from "@codemirror/state";
|
||||
import { extendedMarkdownLanguage } from "../common/markdown_parser/parser.ts";
|
||||
import { parseCommand } from "../common/command.ts";
|
||||
|
||||
export function createEditorState(
|
||||
client: Client,
|
||||
@@ -270,28 +270,24 @@ export function createCommandKeyBindings(client: Client): KeyBinding[] {
|
||||
if (client.settings?.shortcuts) {
|
||||
for (const shortcut of client.settings.shortcuts) {
|
||||
// Figure out if we're using the command link syntax here, if so: parse it out
|
||||
const commandMatch = commandLinkRegex.exec(shortcut.command);
|
||||
let cleanCommandName = shortcut.command;
|
||||
let args: any[] = [];
|
||||
if (commandMatch) {
|
||||
cleanCommandName = commandMatch[1];
|
||||
args = commandMatch[5] ? JSON.parse(`[${commandMatch[5]}]`) : [];
|
||||
}
|
||||
if (args.length === 0) {
|
||||
const parsedCommand = parseCommand(shortcut.command);
|
||||
if (parsedCommand.args.length === 0) {
|
||||
// If there was no "specialization" of this command (that is, we effectively created a keybinding for an existing command but with arguments), let's add it to the overridden command set:
|
||||
overriddenCommands.add(cleanCommandName);
|
||||
overriddenCommands.add(parsedCommand.name);
|
||||
}
|
||||
commandKeyBindings.push({
|
||||
key: shortcut.key,
|
||||
mac: shortcut.mac,
|
||||
run: (): boolean => {
|
||||
client.runCommandByName(cleanCommandName, args).catch((e: any) => {
|
||||
console.error(e);
|
||||
client.flashNotification(
|
||||
`Error running command: ${e.message}`,
|
||||
"error",
|
||||
);
|
||||
}).then(() => {
|
||||
client.runCommandByName(parsedCommand.name, parsedCommand.args).catch(
|
||||
(e: any) => {
|
||||
console.error(e);
|
||||
client.flashNotification(
|
||||
`Error running command: ${e.message}`,
|
||||
"error",
|
||||
);
|
||||
},
|
||||
).then(() => {
|
||||
// Always be focusing the editor after running a command
|
||||
client.focus();
|
||||
});
|
||||
|
||||
+20
-34
@@ -1,4 +1,4 @@
|
||||
import { isMacLike, safeRun } from "../common/util.ts";
|
||||
import { safeRun } from "../common/util.ts";
|
||||
import { Confirm, Prompt } from "./components/basic_modals.tsx";
|
||||
import { CommandPalette } from "./components/command_palette.tsx";
|
||||
import { FilterList } from "./components/filter.tsx";
|
||||
@@ -7,12 +7,9 @@ import { TopBar } from "./components/top_bar.tsx";
|
||||
import reducer from "./reducer.ts";
|
||||
import { Action, AppViewState, initialViewState } from "./types.ts";
|
||||
import {
|
||||
BookIcon,
|
||||
HomeIcon,
|
||||
featherIcons,
|
||||
preactRender,
|
||||
RefreshCwIcon,
|
||||
runScopeHandlers,
|
||||
TerminalIcon,
|
||||
useEffect,
|
||||
useReducer,
|
||||
} from "./deps.ts";
|
||||
@@ -20,6 +17,7 @@ import type { Client } from "./client.ts";
|
||||
import { Panel } from "./components/panel.tsx";
|
||||
import { h } from "./deps.ts";
|
||||
import { sleep } from "$sb/lib/async.ts";
|
||||
import { parseCommand } from "../common/command.ts";
|
||||
|
||||
export class MainUI {
|
||||
viewState: AppViewState = initialViewState;
|
||||
@@ -210,10 +208,11 @@ export class MainUI {
|
||||
client.focus();
|
||||
}}
|
||||
actionButtons={[
|
||||
...!window.silverBulletConfig.syncOnly
|
||||
...(!window.silverBulletConfig.syncOnly &&
|
||||
!viewState.settings.hideSyncButton)
|
||||
// If we support syncOnly, don't show this toggle button
|
||||
? [{
|
||||
icon: RefreshCwIcon,
|
||||
icon: featherIcons.RefreshCw,
|
||||
description: this.client.syncMode
|
||||
? "Currently in Sync mode, click to switch to Online mode"
|
||||
: "Currently in Online mode, click to switch to Sync mode",
|
||||
@@ -241,33 +240,20 @@ export class MainUI {
|
||||
},
|
||||
}]
|
||||
: [],
|
||||
{
|
||||
icon: HomeIcon,
|
||||
description: `Go to the index page (Alt-h)`,
|
||||
callback: () => {
|
||||
client.navigate({ page: "", pos: 0 });
|
||||
// And let's make sure all panels are closed
|
||||
dispatch({ type: "hide-filterbox" });
|
||||
},
|
||||
href: "",
|
||||
},
|
||||
{
|
||||
icon: BookIcon,
|
||||
description: `Open page (${isMacLike() ? "Cmd-k" : "Ctrl-k"})`,
|
||||
callback: () => {
|
||||
client.startPageNavigate("page");
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: TerminalIcon,
|
||||
description: `Run command (${isMacLike() ? "Cmd-/" : "Ctrl-/"})`,
|
||||
callback: () => {
|
||||
dispatch({
|
||||
type: "show-palette",
|
||||
context: client.getContext(),
|
||||
});
|
||||
},
|
||||
},
|
||||
...viewState.settings.actionButtons.map((button) => {
|
||||
const parsedCommand = parseCommand(button.command);
|
||||
return {
|
||||
icon: (featherIcons as any)[button.icon],
|
||||
description: button.description || "",
|
||||
callback: () => {
|
||||
client.runCommandByName(
|
||||
parsedCommand.name,
|
||||
parsedCommand.args,
|
||||
);
|
||||
},
|
||||
href: "",
|
||||
};
|
||||
}),
|
||||
]}
|
||||
rhs={!!viewState.panels.rhs.mode && (
|
||||
<div
|
||||
|
||||
@@ -20,6 +20,8 @@ export type CommandDef = {
|
||||
// Bind to keyboard shortcut
|
||||
key?: string;
|
||||
mac?: string;
|
||||
|
||||
hide?: boolean;
|
||||
};
|
||||
|
||||
export type AppCommand = {
|
||||
|
||||
@@ -45,6 +45,11 @@ export default function reducer(
|
||||
...state,
|
||||
syncFailures: action.syncSuccess ? 0 : state.syncFailures + 1,
|
||||
};
|
||||
case "settings-loaded":
|
||||
return {
|
||||
...state,
|
||||
settings: action.settings,
|
||||
};
|
||||
case "update-page-list": {
|
||||
// Let's move over any "lastOpened" times to the "allPages" list
|
||||
const oldPageMeta = new Map(
|
||||
|
||||
+16
-1
@@ -1,6 +1,7 @@
|
||||
import { Manifest } from "../common/manifest.ts";
|
||||
import { PageMeta } from "$sb/types.ts";
|
||||
import { AppCommand } from "./hooks/command.ts";
|
||||
import { defaultSettings } from "../common/util.ts";
|
||||
|
||||
// Used by FilterBox
|
||||
export type FilterOption = {
|
||||
@@ -26,11 +27,20 @@ export type Shortcut = {
|
||||
command: string;
|
||||
};
|
||||
|
||||
export type ActionButton = {
|
||||
icon: string;
|
||||
description?: string;
|
||||
command: string;
|
||||
args?: any[];
|
||||
};
|
||||
|
||||
export type BuiltinSettings = {
|
||||
indexPage: string;
|
||||
customStyles?: string | string[];
|
||||
plugOverrides?: Record<string, Partial<Manifest>>;
|
||||
shortcuts?: Shortcut[];
|
||||
hideSyncButton?: boolean;
|
||||
actionButtons: ActionButton[];
|
||||
// Format: compatible with docker ignore
|
||||
spaceIgnore?: string;
|
||||
};
|
||||
@@ -44,6 +54,8 @@ export type PanelConfig = {
|
||||
export type AppViewState = {
|
||||
currentPage?: string;
|
||||
currentPageMeta?: PageMeta;
|
||||
allPages: PageMeta[];
|
||||
|
||||
isLoading: boolean;
|
||||
showPageNavigator: boolean;
|
||||
showCommandPalette: boolean;
|
||||
@@ -52,11 +64,12 @@ export type AppViewState = {
|
||||
syncFailures: number; // Reset everytime a sync succeeds
|
||||
progressPerc?: number;
|
||||
panels: { [key: string]: PanelConfig };
|
||||
allPages: PageMeta[];
|
||||
commands: Map<string, AppCommand>;
|
||||
notifications: Notification[];
|
||||
recentCommands: Map<string, Date>;
|
||||
|
||||
settings: BuiltinSettings;
|
||||
|
||||
uiOptions: {
|
||||
vimMode: boolean;
|
||||
darkMode: boolean;
|
||||
@@ -104,6 +117,7 @@ export const initialViewState: AppViewState = {
|
||||
bhs: {},
|
||||
modal: {},
|
||||
},
|
||||
settings: defaultSettings,
|
||||
allPages: [],
|
||||
commands: new Map(),
|
||||
recentCommands: new Map(),
|
||||
@@ -126,6 +140,7 @@ export type Action =
|
||||
| { type: "page-saved" }
|
||||
| { type: "sync-change"; syncSuccess: boolean }
|
||||
| { type: "update-page-list"; allPages: PageMeta[] }
|
||||
| { type: "settings-loaded"; settings: BuiltinSettings }
|
||||
| { type: "start-navigate"; mode: "page" | "template" }
|
||||
| { type: "stop-navigate" }
|
||||
| {
|
||||
|
||||
Reference in New Issue
Block a user