Skip to content

Commit

Permalink
0.8.0 (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
LiamRiddell authored Nov 27, 2023
1 parent 5a87cf6 commit 6c0bd6f
Show file tree
Hide file tree
Showing 25 changed files with 3,974 additions and 96 deletions.
106 changes: 21 additions & 85 deletions src/codemirror/MarkdownEditorViewPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { ResultWidget } from "@/codemirror/widgets/ResultWidget";
import { pluginEventBus } from "@/eventbus/PluginEventBus";
import { IResult } from "@/results/definition/IResult";
import { Pipeline } from "@/pipelines/definition/Pipeline";
import { SharedCommentsRemovalStage } from "@/pipelines/stages/CommentsRemovalStage";
import { SharedMarkdownRemovalStage } from "@/pipelines/stages/MarkdownRemovalStage";
import { VariableProcessingStage } from "@/pipelines/stages/VariableProcessingStage";
import UserSettings from "@/settings/UserSettings";
import { logger } from "@/utilities/Logger";
// @ts-expect-error
Expand Down Expand Up @@ -28,15 +31,19 @@ export class MarkdownEditorViewPlugin implements PluginValue {
"list",
"HyperMD-list-line",
];
private variableAssignmentRegex = new RegExp(/^(\$\w+)\s+=/);
private variableSubstitutionRegex = new RegExp(/(\$\w+)/g);
private variableMap = new Map<string, IResult<any>>();

private processingPipeline: Pipeline<string>;

constructor(view: EditorView) {
logger.debug(`[SolveViewPlugin] Constructer`);

this.userSettings = UserSettings.getInstance();

this.processingPipeline = new Pipeline<string>()
.addStage(SharedMarkdownRemovalStage)
.addStage(SharedCommentsRemovalStage)
.addStage(new VariableProcessingStage());

this.decorations = this.buildDecorations(view);
}

Expand All @@ -47,8 +54,6 @@ export class MarkdownEditorViewPlugin implements PluginValue {
EPluginStatus.Solving
);

this.variableMap.clear();

// console.time("[Solve] MarkdownEditorViewPlugin.buildDecorations");
this.decorations = this.buildDecorations(update.view);
// console.timeEnd(
Expand Down Expand Up @@ -87,6 +92,13 @@ export class MarkdownEditorViewPlugin implements PluginValue {
from,
to,
enter: (node: SyntaxNodeRef) => {
// console.log(
// node.type.name,
// node.from,
// node.to,
// view.state.doc.sliceString(node.from, node.to)
// );

if (this.isNodeIgnoredFromMask(node.type.name)) {
return;
}
Expand Down Expand Up @@ -146,15 +158,9 @@ export class MarkdownEditorViewPlugin implements PluginValue {
continue;
}

// Ignored nodes e.g. block qoutes (>), lists (-), checked list ([ ]) will remove the
// markdown formatting at the start of the string.
lineText = lineText.replace(
/^(?:(?:[-+*>]|(?:\[\s\])|(?:\d+\.))\s)+/m,
""
);

// Variable Support (Scoped to view)
lineText = this.handleVariables(lineText);
// logger.debug("Before Pipeline:", lineText);
lineText = this.processingPipeline.process(lineText);
// logger.debug("After Pipeline:", lineText);

// The line is valid and decoration can be provided.
const decoration = this.provideDecoration(
Expand Down Expand Up @@ -245,74 +251,4 @@ export class MarkdownEditorViewPlugin implements PluginValue {
side: 1,
});
}

//#region Variables
private handleVariables(sentence: string) {
const variableAssignmentMatch = sentence.match(
this.variableAssignmentRegex
);

if (variableAssignmentMatch && variableAssignmentMatch.length > 0) {
this.parseVariable(variableAssignmentMatch[1], sentence);
} else {
const variableMatches = [
...sentence.matchAll(this.variableSubstitutionRegex),
];

if (variableMatches.length > 0) {
sentence = this.substituteVariables(sentence, variableMatches);
}
}

return sentence;
}

private parseVariable(name: string, expression: string) {
const assignmentPosition = expression.indexOf("=");
if (assignmentPosition > -1) {
const assignmentExpression = expression.substring(
assignmentPosition + 1
);

const result = solveProviderManager.provideFirst(
assignmentExpression,
true
);

if (result !== undefined) {
this.variableMap.set(name, result as any as IResult<any>);
}
}

return false;
}

private substituteVariables(
expression: string,
variablesMatches: RegExpMatchArray[]
) {
let expressionSubstituted = expression;

for (let i = 0; i < variablesMatches.length; i++) {
const variableMatch = variablesMatches[i];

if (!variableMatch) continue;

const variableName = variableMatch[0];

if (this.variableMap.has(variableName)) {
const variableValue = this.variableMap.get(variableName);

if (variableValue) {
expressionSubstituted = expressionSubstituted.replace(
variableName,
variableValue.value
);
}
}
}

return expressionSubstituted;
}
//#endregion
}
1 change: 1 addition & 0 deletions src/codemirror/widgets/ResultWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class ResultWidget extends WidgetType {
).number;

const div = document.createElement("div");
div.id = `osr-${this.lineNumber}`;
div.title = "Click to commit this result";

div.addEventListener("click", () => {
Expand Down
7 changes: 7 additions & 0 deletions src/errors/EmptyPipelineError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export class EmptyPipelineError extends Error {
constructor(message?: string) {
super(message || "The executed pipeline has no stages.");
this.name = "EmptyPipelineError";
Error.captureStackTrace(this, EmptyPipelineError);
}
}
4 changes: 4 additions & 0 deletions src/grammars/arithmetic/BasicArithmetic.ohm
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,17 @@ BasicArithmetic {

multiply
= "*"
| "\\*" // Escaped \* for markdown
| "\u{00D7}" // ×
| caseInsensitive<"x">
| caseInsensitive<"times by">
| caseInsensitive<"times">
| caseInsensitive<"multiply by">
| caseInsensitive<"multiply">

divide
= "/"
| "\u{00F7}" // ÷
| caseInsensitive<"divide by">
| caseInsensitive<"divide">

Expand Down
2 changes: 1 addition & 1 deletion src/grammars/arithmetic/BasicArithmetic.ohm-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/grammars/function/FunctionArithmetic.ohm-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/grammars/percentage/PercentageArithmetic.ohm-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/grammars/uom/UnitsOfMeasurement.ohm-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/grammars/vector/Vector2Arithmetic.ohm-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/grammars/vector/Vector3Arithmetic.ohm-bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/grammars/vector/Vector4Arithmetic.ohm-bundle.js

Large diffs are not rendered by default.

73 changes: 70 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { solveProviderManager } from "@/providers/ProviderManager";
import { DEFAULT_SETTINGS } from "@/settings/PluginSettings";
import { SettingTab } from "@/settings/SettingsTab";
import UserSettings from "@/settings/UserSettings";
import { minValueExcludingBelow } from "@/utilities/Array";
import { logger } from "@/utilities/Logger";
import { insertAtIndex } from "@/utilities/String";
import { ViewPlugin } from "@codemirror/view";
import { Plugin } from "obsidian";
import { Notice, Plugin } from "obsidian";

export default class SolvePlugin extends Plugin {
settings: UserSettings;
Expand Down Expand Up @@ -54,6 +56,8 @@ export default class SolvePlugin extends Plugin {

await this.addStatusBarCompanion();
logger.debug(`[Solve] Added: Status Bar Companion`);

await this.registerCommands();
}

public onunload() {
Expand Down Expand Up @@ -132,6 +136,50 @@ export default class SolvePlugin extends Plugin {
pluginEventBus.emit(EPluginEvent.StatusBarUpdate, EPluginStatus.Idle);
}

private async registerCommands() {
this.addCommand({
id: "commit-result-current-line",
name: "Commit result on current line",
editorCallback(editor, ctx) {
const currentLineNumber = editor.getCursor("head").line + 1;

const { containerEl } = editor as any;

const resultElement = (
containerEl as HTMLElement
).querySelector<HTMLElement>(`#osr-${currentLineNumber}`);

if (resultElement) {
resultElement.click();
} else {
new Notice(
"Solve: Failed to commit, no result found on the current line."
);
}
},
});

this.addCommand({
id: "commit-result-all-visible",
name: "Commit all visible results",
editorCallback(editor, ctx) {
const { containerEl } = editor as any;

const resultElements = (
containerEl as HTMLElement
).querySelectorAll<HTMLElement>(`.os-result`);

for (let i = 0; i < resultElements.length; i++) {
const resultElement = resultElements[i];

if (resultElement) {
resultElement.click();
}
}
},
});
}

public async setStatusBarCompanionVisibility(visible: boolean) {
if (visible) {
this.statusBarItemEl.style.display = "inline-block";
Expand All @@ -155,13 +203,32 @@ export default class SolvePlugin extends Plugin {
private async onWriteResultEvent(lineNumber: number, resultValue: string) {
const lineNumberZeroIndexed = Math.max(0, lineNumber - 1);

const lineText = this.app.workspace.activeEditor?.editor?.getLine(
let lineText = this.app.workspace.activeEditor?.editor?.getLine(
lineNumberZeroIndexed
);

if (typeof lineText === "undefined") {
return;
}

const commentsBeginIndex = minValueExcludingBelow([
lineText.indexOf("#"),
lineText.indexOf("//"),
]);

if (commentsBeginIndex > -1) {
lineText = insertAtIndex(
lineText,
commentsBeginIndex,
` ${resultValue} ` // Whitespace normalised for format.. Expression Result Comment
);
} else {
lineText = `${lineText?.trimEnd()} ${resultValue}`;
}

this.app.workspace.activeEditor?.editor?.setLine(
lineNumberZeroIndexed,
`${lineText?.trimEnd()} ${resultValue}`
lineText
);
}
}
28 changes: 28 additions & 0 deletions src/pipelines/definition/Pipeline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { EmptyPipelineError } from "@/errors/EmptyPipelineError";
import { IPipelineStage } from "@/pipelines/definition/stages/IPipelineStage";

export class Pipeline<T> {
private firstStage: IPipelineStage<T> | null = null;
private lastStage: IPipelineStage<T> | null = null;

addStage(stage: IPipelineStage<T>): Pipeline<T> {
if (!this.firstStage) {
this.firstStage = this.lastStage = stage;
} else {
if (this.lastStage) {
this.lastStage.next(stage);
}
this.lastStage = stage;
}

return this;
}

process(request: T): T {
if (!this.firstStage) {
throw new EmptyPipelineError();
}

return this.firstStage.process(request);
}
}
29 changes: 29 additions & 0 deletions src/pipelines/definition/PipelineAsync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { EmptyPipelineError } from "@/errors/EmptyPipelineError";
import { IPipelineAsyncStage } from "@/pipelines/definition/stages/IPipelineAsyncStage";

export class PipelineAsync<T> {
private firstStage: IPipelineAsyncStage<T> | null = null;
private lastStage: IPipelineAsyncStage<T> | null = null;

addStage(stage: IPipelineAsyncStage<T>): PipelineAsync<T> {
if (!this.firstStage) {
this.firstStage = this.lastStage = stage;
} else {
if (this.lastStage) {
this.lastStage.next(stage);
}

this.lastStage = stage;
}

return this;
}

async process(request: T): Promise<T> {
if (!this.firstStage) {
throw new EmptyPipelineError();
}

return this.firstStage.process(request);
}
}
20 changes: 20 additions & 0 deletions src/pipelines/definition/stages/BasePipelineAsyncStage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IPipelineAsyncStage } from "@/pipelines/definition/stages/IPipelineAsyncStage";

export abstract class BasePipelineAsyncStage<T>
implements IPipelineAsyncStage<T>
{
private nextStage: IPipelineAsyncStage<T> | null = null;

next(stage: IPipelineAsyncStage<T>): IPipelineAsyncStage<T> {
this.nextStage = stage;
return stage;
}

async process(request: T): Promise<T> {
request = await this.execute(request);
return this.nextStage ? this.nextStage.process(request) : request;
}

// Execute the stages user code.
protected abstract execute(request: T): Promise<T>;
}
18 changes: 18 additions & 0 deletions src/pipelines/definition/stages/BasePipelineStage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { IPipelineStage } from "@/pipelines/definition/stages/IPipelineStage";

export abstract class BasePipelineStage<T> implements IPipelineStage<T> {
private nextStage: IPipelineStage<T> | null = null;

next(stage: IPipelineStage<T>): IPipelineStage<T> {
this.nextStage = stage;
return stage;
}

process(request: T): T {
request = this.execute(request);
return this.nextStage ? this.nextStage.process(request) : request;
}

// Execute the stage's user code.
protected abstract execute(request: T): T;
}
4 changes: 4 additions & 0 deletions src/pipelines/definition/stages/IPipelineAsyncStage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IPipelineAsyncStage<T> {
next(stage: IPipelineAsyncStage<T>): IPipelineAsyncStage<T>;
process(request: T): Promise<T>;
}
Loading

0 comments on commit 6c0bd6f

Please sign in to comment.